e9692b8037
Most places in the registry were using string types to refer to repository names. This changes them to use reference.Named, so the type system can enforce validation of the naming rules. Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
302 lines
8.1 KiB
Go
302 lines
8.1 KiB
Go
package v2
|
|
|
|
import (
|
|
"net/http"
|
|
"net/url"
|
|
"testing"
|
|
|
|
"github.com/docker/distribution/reference"
|
|
)
|
|
|
|
type urlBuilderTestCase struct {
|
|
description string
|
|
expectedPath string
|
|
build func() (string, error)
|
|
}
|
|
|
|
func makeURLBuilderTestCases(urlBuilder *URLBuilder) []urlBuilderTestCase {
|
|
fooBarRef, _ := reference.ParseNamed("foo/bar")
|
|
return []urlBuilderTestCase{
|
|
{
|
|
description: "test base url",
|
|
expectedPath: "/v2/",
|
|
build: urlBuilder.BuildBaseURL,
|
|
},
|
|
{
|
|
description: "test tags url",
|
|
expectedPath: "/v2/foo/bar/tags/list",
|
|
build: func() (string, error) {
|
|
return urlBuilder.BuildTagsURL(fooBarRef)
|
|
},
|
|
},
|
|
{
|
|
description: "test manifest url",
|
|
expectedPath: "/v2/foo/bar/manifests/tag",
|
|
build: func() (string, error) {
|
|
return urlBuilder.BuildManifestURL(fooBarRef, "tag")
|
|
},
|
|
},
|
|
{
|
|
description: "build blob url",
|
|
expectedPath: "/v2/foo/bar/blobs/sha256:3b3692957d439ac1928219a83fac91e7bf96c153725526874673ae1f2023f8d5",
|
|
build: func() (string, error) {
|
|
return urlBuilder.BuildBlobURL(fooBarRef, "sha256:3b3692957d439ac1928219a83fac91e7bf96c153725526874673ae1f2023f8d5")
|
|
},
|
|
},
|
|
{
|
|
description: "build blob upload url",
|
|
expectedPath: "/v2/foo/bar/blobs/uploads/",
|
|
build: func() (string, error) {
|
|
return urlBuilder.BuildBlobUploadURL(fooBarRef)
|
|
},
|
|
},
|
|
{
|
|
description: "build blob upload url with digest and size",
|
|
expectedPath: "/v2/foo/bar/blobs/uploads/?digest=sha256%3A3b3692957d439ac1928219a83fac91e7bf96c153725526874673ae1f2023f8d5&size=10000",
|
|
build: func() (string, error) {
|
|
return urlBuilder.BuildBlobUploadURL(fooBarRef, url.Values{
|
|
"size": []string{"10000"},
|
|
"digest": []string{"sha256:3b3692957d439ac1928219a83fac91e7bf96c153725526874673ae1f2023f8d5"},
|
|
})
|
|
},
|
|
},
|
|
{
|
|
description: "build blob upload chunk url",
|
|
expectedPath: "/v2/foo/bar/blobs/uploads/uuid-part",
|
|
build: func() (string, error) {
|
|
return urlBuilder.BuildBlobUploadChunkURL(fooBarRef, "uuid-part")
|
|
},
|
|
},
|
|
{
|
|
description: "build blob upload chunk url with digest and size",
|
|
expectedPath: "/v2/foo/bar/blobs/uploads/uuid-part?digest=sha256%3A3b3692957d439ac1928219a83fac91e7bf96c153725526874673ae1f2023f8d5&size=10000",
|
|
build: func() (string, error) {
|
|
return urlBuilder.BuildBlobUploadChunkURL(fooBarRef, "uuid-part", url.Values{
|
|
"size": []string{"10000"},
|
|
"digest": []string{"sha256:3b3692957d439ac1928219a83fac91e7bf96c153725526874673ae1f2023f8d5"},
|
|
})
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
// TestURLBuilder tests the various url building functions, ensuring they are
|
|
// returning the expected values.
|
|
func TestURLBuilder(t *testing.T) {
|
|
roots := []string{
|
|
"http://example.com",
|
|
"https://example.com",
|
|
"http://localhost:5000",
|
|
"https://localhost:5443",
|
|
}
|
|
|
|
for _, root := range roots {
|
|
urlBuilder, err := NewURLBuilderFromString(root)
|
|
if err != nil {
|
|
t.Fatalf("unexpected error creating urlbuilder: %v", err)
|
|
}
|
|
|
|
for _, testCase := range makeURLBuilderTestCases(urlBuilder) {
|
|
url, err := testCase.build()
|
|
if err != nil {
|
|
t.Fatalf("%s: error building url: %v", testCase.description, err)
|
|
}
|
|
|
|
expectedURL := root + testCase.expectedPath
|
|
|
|
if url != expectedURL {
|
|
t.Fatalf("%s: %q != %q", testCase.description, url, expectedURL)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestURLBuilderWithPrefix(t *testing.T) {
|
|
roots := []string{
|
|
"http://example.com/prefix/",
|
|
"https://example.com/prefix/",
|
|
"http://localhost:5000/prefix/",
|
|
"https://localhost:5443/prefix/",
|
|
}
|
|
|
|
for _, root := range roots {
|
|
urlBuilder, err := NewURLBuilderFromString(root)
|
|
if err != nil {
|
|
t.Fatalf("unexpected error creating urlbuilder: %v", err)
|
|
}
|
|
|
|
for _, testCase := range makeURLBuilderTestCases(urlBuilder) {
|
|
url, err := testCase.build()
|
|
if err != nil {
|
|
t.Fatalf("%s: error building url: %v", testCase.description, err)
|
|
}
|
|
|
|
expectedURL := root[0:len(root)-1] + testCase.expectedPath
|
|
|
|
if url != expectedURL {
|
|
t.Fatalf("%s: %q != %q", testCase.description, url, expectedURL)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
type builderFromRequestTestCase struct {
|
|
request *http.Request
|
|
base string
|
|
}
|
|
|
|
func TestBuilderFromRequest(t *testing.T) {
|
|
u, err := url.Parse("http://example.com")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
forwardedProtoHeader := make(http.Header, 1)
|
|
forwardedProtoHeader.Set("X-Forwarded-Proto", "https")
|
|
|
|
forwardedHostHeader1 := make(http.Header, 1)
|
|
forwardedHostHeader1.Set("X-Forwarded-Host", "first.example.com")
|
|
|
|
forwardedHostHeader2 := make(http.Header, 1)
|
|
forwardedHostHeader2.Set("X-Forwarded-Host", "first.example.com, proxy1.example.com")
|
|
|
|
testRequests := []struct {
|
|
request *http.Request
|
|
base string
|
|
configHost url.URL
|
|
}{
|
|
{
|
|
request: &http.Request{URL: u, Host: u.Host},
|
|
base: "http://example.com",
|
|
},
|
|
|
|
{
|
|
request: &http.Request{URL: u, Host: u.Host, Header: forwardedProtoHeader},
|
|
base: "http://example.com",
|
|
},
|
|
{
|
|
request: &http.Request{URL: u, Host: u.Host, Header: forwardedProtoHeader},
|
|
base: "https://example.com",
|
|
},
|
|
{
|
|
request: &http.Request{URL: u, Host: u.Host, Header: forwardedHostHeader1},
|
|
base: "http://first.example.com",
|
|
},
|
|
{
|
|
request: &http.Request{URL: u, Host: u.Host, Header: forwardedHostHeader2},
|
|
base: "http://first.example.com",
|
|
},
|
|
{
|
|
request: &http.Request{URL: u, Host: u.Host, Header: forwardedHostHeader2},
|
|
base: "https://third.example.com:5000",
|
|
configHost: url.URL{
|
|
Scheme: "https",
|
|
Host: "third.example.com:5000",
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tr := range testRequests {
|
|
var builder *URLBuilder
|
|
if tr.configHost.Scheme != "" && tr.configHost.Host != "" {
|
|
builder = NewURLBuilder(&tr.configHost)
|
|
} else {
|
|
builder = NewURLBuilderFromRequest(tr.request)
|
|
}
|
|
|
|
for _, testCase := range makeURLBuilderTestCases(builder) {
|
|
buildURL, err := testCase.build()
|
|
if err != nil {
|
|
t.Fatalf("%s: error building url: %v", testCase.description, err)
|
|
}
|
|
|
|
var expectedURL string
|
|
proto, ok := tr.request.Header["X-Forwarded-Proto"]
|
|
if !ok {
|
|
expectedURL = tr.base + testCase.expectedPath
|
|
} else {
|
|
urlBase, err := url.Parse(tr.base)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
urlBase.Scheme = proto[0]
|
|
expectedURL = urlBase.String() + testCase.expectedPath
|
|
}
|
|
|
|
if buildURL != expectedURL {
|
|
t.Fatalf("%s: %q != %q", testCase.description, buildURL, expectedURL)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestBuilderFromRequestWithPrefix(t *testing.T) {
|
|
u, err := url.Parse("http://example.com/prefix/v2/")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
forwardedProtoHeader := make(http.Header, 1)
|
|
forwardedProtoHeader.Set("X-Forwarded-Proto", "https")
|
|
|
|
testRequests := []struct {
|
|
request *http.Request
|
|
base string
|
|
configHost url.URL
|
|
}{
|
|
{
|
|
request: &http.Request{URL: u, Host: u.Host},
|
|
base: "http://example.com/prefix/",
|
|
},
|
|
|
|
{
|
|
request: &http.Request{URL: u, Host: u.Host, Header: forwardedProtoHeader},
|
|
base: "http://example.com/prefix/",
|
|
},
|
|
{
|
|
request: &http.Request{URL: u, Host: u.Host, Header: forwardedProtoHeader},
|
|
base: "https://example.com/prefix/",
|
|
},
|
|
{
|
|
request: &http.Request{URL: u, Host: u.Host, Header: forwardedProtoHeader},
|
|
base: "https://subdomain.example.com/prefix/",
|
|
configHost: url.URL{
|
|
Scheme: "https",
|
|
Host: "subdomain.example.com",
|
|
Path: "/prefix/",
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tr := range testRequests {
|
|
var builder *URLBuilder
|
|
if tr.configHost.Scheme != "" && tr.configHost.Host != "" {
|
|
builder = NewURLBuilder(&tr.configHost)
|
|
} else {
|
|
builder = NewURLBuilderFromRequest(tr.request)
|
|
}
|
|
|
|
for _, testCase := range makeURLBuilderTestCases(builder) {
|
|
buildURL, err := testCase.build()
|
|
if err != nil {
|
|
t.Fatalf("%s: error building url: %v", testCase.description, err)
|
|
}
|
|
var expectedURL string
|
|
proto, ok := tr.request.Header["X-Forwarded-Proto"]
|
|
if !ok {
|
|
expectedURL = tr.base[0:len(tr.base)-1] + testCase.expectedPath
|
|
} else {
|
|
urlBase, err := url.Parse(tr.base)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
urlBase.Scheme = proto[0]
|
|
expectedURL = urlBase.String()[0:len(urlBase.String())-1] + testCase.expectedPath
|
|
}
|
|
|
|
if buildURL != expectedURL {
|
|
t.Fatalf("%s: %q != %q", testCase.description, buildURL, expectedURL)
|
|
}
|
|
}
|
|
}
|
|
}
|