commit
						6cd2945b5c
					
				| 
						 | 
					@ -43,9 +43,30 @@ func NewURLBuilderFromString(root string) (*URLBuilder, error) {
 | 
				
			||||||
// NewURLBuilderFromRequest uses information from an *http.Request to
 | 
					// NewURLBuilderFromRequest uses information from an *http.Request to
 | 
				
			||||||
// construct the root url.
 | 
					// construct the root url.
 | 
				
			||||||
func NewURLBuilderFromRequest(r *http.Request) *URLBuilder {
 | 
					func NewURLBuilderFromRequest(r *http.Request) *URLBuilder {
 | 
				
			||||||
 | 
						var scheme string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						forwardedProto := r.Header.Get("X-Forwarded-Proto")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch {
 | 
				
			||||||
 | 
						case len(forwardedProto) > 0:
 | 
				
			||||||
 | 
							scheme = forwardedProto
 | 
				
			||||||
 | 
						case r.TLS != nil:
 | 
				
			||||||
 | 
							scheme = "https"
 | 
				
			||||||
 | 
						case len(r.URL.Scheme) > 0:
 | 
				
			||||||
 | 
							scheme = r.URL.Scheme
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							scheme = "http"
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						host := r.Host
 | 
				
			||||||
 | 
						forwardedHost := r.Header.Get("X-Forwarded-Host")
 | 
				
			||||||
 | 
						if len(forwardedHost) > 0 {
 | 
				
			||||||
 | 
							host = forwardedHost
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	u := &url.URL{
 | 
						u := &url.URL{
 | 
				
			||||||
		Scheme: r.URL.Scheme,
 | 
							Scheme: scheme,
 | 
				
			||||||
		Host:   r.Host,
 | 
							Host:   host,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return NewURLBuilder(u)
 | 
						return NewURLBuilder(u)
 | 
				
			||||||
| 
						 | 
					@ -129,13 +150,28 @@ func (ub *URLBuilder) BuildBlobUploadChunkURL(name, uuid string, values ...url.V
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// clondedRoute returns a clone of the named route from the router. Routes
 | 
					// clondedRoute returns a clone of the named route from the router. Routes
 | 
				
			||||||
// must be cloned to avoid modifying them during url generation.
 | 
					// must be cloned to avoid modifying them during url generation.
 | 
				
			||||||
func (ub *URLBuilder) cloneRoute(name string) *mux.Route {
 | 
					func (ub *URLBuilder) cloneRoute(name string) clonedRoute {
 | 
				
			||||||
	route := new(mux.Route)
 | 
						route := new(mux.Route)
 | 
				
			||||||
	*route = *ub.router.GetRoute(name) // clone the route
 | 
						root := new(url.URL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return route.
 | 
						*route = *ub.router.GetRoute(name) // clone the route
 | 
				
			||||||
		Schemes(ub.root.Scheme).
 | 
						*root = *ub.root
 | 
				
			||||||
		Host(ub.root.Host)
 | 
					
 | 
				
			||||||
 | 
						return clonedRoute{Route: route, root: root}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type clonedRoute struct {
 | 
				
			||||||
 | 
						*mux.Route
 | 
				
			||||||
 | 
						root *url.URL
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (cr clonedRoute) URL(pairs ...string) (*url.URL, error) {
 | 
				
			||||||
 | 
						routeURL, err := cr.Route.URL(pairs...)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return cr.root.ResolveReference(routeURL), nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// appendValuesURL appends the parameters to the url.
 | 
					// appendValuesURL appends the parameters to the url.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,67 +1,55 @@
 | 
				
			||||||
package v2
 | 
					package v2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"net/http"
 | 
				
			||||||
	"net/url"
 | 
						"net/url"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type urlBuilderTestCase struct {
 | 
					type urlBuilderTestCase struct {
 | 
				
			||||||
	description  string
 | 
						description  string
 | 
				
			||||||
	expected    string
 | 
						expectedPath string
 | 
				
			||||||
	build        func() (string, error)
 | 
						build        func() (string, error)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// TestURLBuilder tests the various url building functions, ensuring they are
 | 
					func makeURLBuilderTestCases(urlBuilder *URLBuilder) []urlBuilderTestCase {
 | 
				
			||||||
// returning the expected values.
 | 
						return []urlBuilderTestCase{
 | 
				
			||||||
func TestURLBuilder(t *testing.T) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	root := "http://localhost:5000/"
 | 
					 | 
				
			||||||
	urlBuilder, err := NewURLBuilderFromString(root)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatalf("unexpected error creating urlbuilder: %v", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for _, testcase := range []struct {
 | 
					 | 
				
			||||||
		description string
 | 
					 | 
				
			||||||
		expected    string
 | 
					 | 
				
			||||||
		build       func() (string, error)
 | 
					 | 
				
			||||||
	}{
 | 
					 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			description:  "test base url",
 | 
								description:  "test base url",
 | 
				
			||||||
			expected:    "http://localhost:5000/v2/",
 | 
								expectedPath: "/v2/",
 | 
				
			||||||
			build:        urlBuilder.BuildBaseURL,
 | 
								build:        urlBuilder.BuildBaseURL,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			description:  "test tags url",
 | 
								description:  "test tags url",
 | 
				
			||||||
			expected:    "http://localhost:5000/v2/foo/bar/tags/list",
 | 
								expectedPath: "/v2/foo/bar/tags/list",
 | 
				
			||||||
			build: func() (string, error) {
 | 
								build: func() (string, error) {
 | 
				
			||||||
				return urlBuilder.BuildTagsURL("foo/bar")
 | 
									return urlBuilder.BuildTagsURL("foo/bar")
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			description:  "test manifest url",
 | 
								description:  "test manifest url",
 | 
				
			||||||
			expected:    "http://localhost:5000/v2/foo/bar/manifests/tag",
 | 
								expectedPath: "/v2/foo/bar/manifests/tag",
 | 
				
			||||||
			build: func() (string, error) {
 | 
								build: func() (string, error) {
 | 
				
			||||||
				return urlBuilder.BuildManifestURL("foo/bar", "tag")
 | 
									return urlBuilder.BuildManifestURL("foo/bar", "tag")
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			description:  "build blob url",
 | 
								description:  "build blob url",
 | 
				
			||||||
			expected:    "http://localhost:5000/v2/foo/bar/blobs/tarsum.v1+sha256:abcdef0123456789",
 | 
								expectedPath: "/v2/foo/bar/blobs/tarsum.v1+sha256:abcdef0123456789",
 | 
				
			||||||
			build: func() (string, error) {
 | 
								build: func() (string, error) {
 | 
				
			||||||
				return urlBuilder.BuildBlobURL("foo/bar", "tarsum.v1+sha256:abcdef0123456789")
 | 
									return urlBuilder.BuildBlobURL("foo/bar", "tarsum.v1+sha256:abcdef0123456789")
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			description:  "build blob upload url",
 | 
								description:  "build blob upload url",
 | 
				
			||||||
			expected:    "http://localhost:5000/v2/foo/bar/blobs/uploads/",
 | 
								expectedPath: "/v2/foo/bar/blobs/uploads/",
 | 
				
			||||||
			build: func() (string, error) {
 | 
								build: func() (string, error) {
 | 
				
			||||||
				return urlBuilder.BuildBlobUploadURL("foo/bar")
 | 
									return urlBuilder.BuildBlobUploadURL("foo/bar")
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			description:  "build blob upload url with digest and size",
 | 
								description:  "build blob upload url with digest and size",
 | 
				
			||||||
			expected:    "http://localhost:5000/v2/foo/bar/blobs/uploads/?digest=tarsum.v1%2Bsha256%3Aabcdef0123456789&size=10000",
 | 
								expectedPath: "/v2/foo/bar/blobs/uploads/?digest=tarsum.v1%2Bsha256%3Aabcdef0123456789&size=10000",
 | 
				
			||||||
			build: func() (string, error) {
 | 
								build: func() (string, error) {
 | 
				
			||||||
				return urlBuilder.BuildBlobUploadURL("foo/bar", url.Values{
 | 
									return urlBuilder.BuildBlobUploadURL("foo/bar", url.Values{
 | 
				
			||||||
					"size":   []string{"10000"},
 | 
										"size":   []string{"10000"},
 | 
				
			||||||
| 
						 | 
					@ -71,14 +59,14 @@ func TestURLBuilder(t *testing.T) {
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			description:  "build blob upload chunk url",
 | 
								description:  "build blob upload chunk url",
 | 
				
			||||||
			expected:    "http://localhost:5000/v2/foo/bar/blobs/uploads/uuid-part",
 | 
								expectedPath: "/v2/foo/bar/blobs/uploads/uuid-part",
 | 
				
			||||||
			build: func() (string, error) {
 | 
								build: func() (string, error) {
 | 
				
			||||||
				return urlBuilder.BuildBlobUploadChunkURL("foo/bar", "uuid-part")
 | 
									return urlBuilder.BuildBlobUploadChunkURL("foo/bar", "uuid-part")
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			description:  "build blob upload chunk url with digest and size",
 | 
								description:  "build blob upload chunk url with digest and size",
 | 
				
			||||||
			expected:    "http://localhost:5000/v2/foo/bar/blobs/uploads/uuid-part?digest=tarsum.v1%2Bsha256%3Aabcdef0123456789&size=10000",
 | 
								expectedPath: "/v2/foo/bar/blobs/uploads/uuid-part?digest=tarsum.v1%2Bsha256%3Aabcdef0123456789&size=10000",
 | 
				
			||||||
			build: func() (string, error) {
 | 
								build: func() (string, error) {
 | 
				
			||||||
				return urlBuilder.BuildBlobUploadChunkURL("foo/bar", "uuid-part", url.Values{
 | 
									return urlBuilder.BuildBlobUploadChunkURL("foo/bar", "uuid-part", url.Values{
 | 
				
			||||||
					"size":   []string{"10000"},
 | 
										"size":   []string{"10000"},
 | 
				
			||||||
| 
						 | 
					@ -86,15 +74,82 @@ func TestURLBuilder(t *testing.T) {
 | 
				
			||||||
				})
 | 
									})
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	} {
 | 
						}
 | 
				
			||||||
		u, err := testcase.build()
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 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 {
 | 
							if err != nil {
 | 
				
			||||||
			t.Fatalf("%s: error building url: %v", testcase.description, err)
 | 
								t.Fatalf("unexpected error creating urlbuilder: %v", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if u != testcase.expected {
 | 
							for _, testCase := range makeURLBuilderTestCases(urlBuilder) {
 | 
				
			||||||
			t.Fatalf("%s: %q != %q", testcase.description, u, testcase.expected)
 | 
								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)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						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",
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						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)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue