628c7fa77b
According to the Apache mod_proxy docs, X-Forwarded-Host can be a comma-separated list of hosts, to which each proxy appends the requested host. We want to grab only the first from this comma-separated list to get the original requested Host when building URLs. Docker-DCO-1.1-Signed-off-by: Josh Hawn <josh.hawn@docker.com> (github: jlhawn)
239 lines
6.1 KiB
Go
239 lines
6.1 KiB
Go
package v2
|
|
|
|
import (
|
|
"net/http"
|
|
"net/url"
|
|
"testing"
|
|
)
|
|
|
|
type urlBuilderTestCase struct {
|
|
description string
|
|
expectedPath string
|
|
build func() (string, error)
|
|
}
|
|
|
|
func makeURLBuilderTestCases(urlBuilder *URLBuilder) []urlBuilderTestCase {
|
|
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("foo/bar")
|
|
},
|
|
},
|
|
{
|
|
description: "test manifest url",
|
|
expectedPath: "/v2/foo/bar/manifests/tag",
|
|
build: func() (string, error) {
|
|
return urlBuilder.BuildManifestURL("foo/bar", "tag")
|
|
},
|
|
},
|
|
{
|
|
description: "build blob url",
|
|
expectedPath: "/v2/foo/bar/blobs/tarsum.v1+sha256:abcdef0123456789",
|
|
build: func() (string, error) {
|
|
return urlBuilder.BuildBlobURL("foo/bar", "tarsum.v1+sha256:abcdef0123456789")
|
|
},
|
|
},
|
|
{
|
|
description: "build blob upload url",
|
|
expectedPath: "/v2/foo/bar/blobs/uploads/",
|
|
build: func() (string, error) {
|
|
return urlBuilder.BuildBlobUploadURL("foo/bar")
|
|
},
|
|
},
|
|
{
|
|
description: "build blob upload url with digest and size",
|
|
expectedPath: "/v2/foo/bar/blobs/uploads/?digest=tarsum.v1%2Bsha256%3Aabcdef0123456789&size=10000",
|
|
build: func() (string, error) {
|
|
return urlBuilder.BuildBlobUploadURL("foo/bar", url.Values{
|
|
"size": []string{"10000"},
|
|
"digest": []string{"tarsum.v1+sha256:abcdef0123456789"},
|
|
})
|
|
},
|
|
},
|
|
{
|
|
description: "build blob upload chunk url",
|
|
expectedPath: "/v2/foo/bar/blobs/uploads/uuid-part",
|
|
build: func() (string, error) {
|
|
return urlBuilder.BuildBlobUploadChunkURL("foo/bar", "uuid-part")
|
|
},
|
|
},
|
|
{
|
|
description: "build blob upload chunk url with digest and size",
|
|
expectedPath: "/v2/foo/bar/blobs/uploads/uuid-part?digest=tarsum.v1%2Bsha256%3Aabcdef0123456789&size=10000",
|
|
build: func() (string, error) {
|
|
return urlBuilder.BuildBlobUploadChunkURL("foo/bar", "uuid-part", url.Values{
|
|
"size": []string{"10000"},
|
|
"digest": []string{"tarsum.v1+sha256:abcdef0123456789"},
|
|
})
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
// 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
|
|
}{
|
|
{
|
|
request: &http.Request{URL: u, Host: u.Host},
|
|
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",
|
|
},
|
|
}
|
|
|
|
for _, tr := range testRequests {
|
|
builder := NewURLBuilderFromRequest(tr.request)
|
|
|
|
for _, testCase := range makeURLBuilderTestCases(builder) {
|
|
url, err := testCase.build()
|
|
if err != nil {
|
|
t.Fatalf("%s: error building url: %v", testCase.description, err)
|
|
}
|
|
|
|
expectedURL := tr.base + testCase.expectedPath
|
|
|
|
if url != expectedURL {
|
|
t.Fatalf("%s: %q != %q", testCase.description, url, 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
|
|
}{
|
|
{
|
|
request: &http.Request{URL: u, Host: u.Host},
|
|
base: "http://example.com/prefix/",
|
|
},
|
|
{
|
|
request: &http.Request{URL: u, Host: u.Host, Header: forwardedProtoHeader},
|
|
base: "https://example.com/prefix/",
|
|
},
|
|
}
|
|
|
|
for _, tr := range testRequests {
|
|
builder := NewURLBuilderFromRequest(tr.request)
|
|
|
|
for _, testCase := range makeURLBuilderTestCases(builder) {
|
|
url, err := testCase.build()
|
|
if err != nil {
|
|
t.Fatalf("%s: error building url: %v", testCase.description, err)
|
|
}
|
|
|
|
expectedURL := tr.base[0:len(tr.base)-1] + testCase.expectedPath
|
|
|
|
if url != expectedURL {
|
|
t.Fatalf("%s: %q != %q", testCase.description, url, expectedURL)
|
|
}
|
|
}
|
|
}
|
|
}
|