Enable URLs returned from the registry to be configured as relative.
Signed-off-by: Richard Scothern <richard.scothern@gmail.com>
This commit is contained in:
parent
22cab6d148
commit
3dd506d896
6 changed files with 210 additions and 91 deletions
|
@ -17,33 +17,35 @@ import (
|
|||
// under "/foo/v2/...". Most application will only provide a schema, host and
|
||||
// port, such as "https://localhost:5000/".
|
||||
type URLBuilder struct {
|
||||
root *url.URL // url root (ie http://localhost/)
|
||||
router *mux.Router
|
||||
root *url.URL // url root (ie http://localhost/)
|
||||
router *mux.Router
|
||||
relative bool
|
||||
}
|
||||
|
||||
// NewURLBuilder creates a URLBuilder with provided root url object.
|
||||
func NewURLBuilder(root *url.URL) *URLBuilder {
|
||||
func NewURLBuilder(root *url.URL, relative bool) *URLBuilder {
|
||||
return &URLBuilder{
|
||||
root: root,
|
||||
router: Router(),
|
||||
root: root,
|
||||
router: Router(),
|
||||
relative: relative,
|
||||
}
|
||||
}
|
||||
|
||||
// NewURLBuilderFromString workes identically to NewURLBuilder except it takes
|
||||
// a string argument for the root, returning an error if it is not a valid
|
||||
// url.
|
||||
func NewURLBuilderFromString(root string) (*URLBuilder, error) {
|
||||
func NewURLBuilderFromString(root string, relative bool) (*URLBuilder, error) {
|
||||
u, err := url.Parse(root)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return NewURLBuilder(u), nil
|
||||
return NewURLBuilder(u, relative), nil
|
||||
}
|
||||
|
||||
// NewURLBuilderFromRequest uses information from an *http.Request to
|
||||
// construct the root url.
|
||||
func NewURLBuilderFromRequest(r *http.Request) *URLBuilder {
|
||||
func NewURLBuilderFromRequest(r *http.Request, relative bool) *URLBuilder {
|
||||
var scheme string
|
||||
|
||||
forwardedProto := r.Header.Get("X-Forwarded-Proto")
|
||||
|
@ -85,7 +87,7 @@ func NewURLBuilderFromRequest(r *http.Request) *URLBuilder {
|
|||
u.Path = requestPath[0 : index+1]
|
||||
}
|
||||
|
||||
return NewURLBuilder(u)
|
||||
return NewURLBuilder(u, relative)
|
||||
}
|
||||
|
||||
// BuildBaseURL constructs a base url for the API, typically just "/v2/".
|
||||
|
@ -194,12 +196,13 @@ func (ub *URLBuilder) cloneRoute(name string) clonedRoute {
|
|||
*route = *ub.router.GetRoute(name) // clone the route
|
||||
*root = *ub.root
|
||||
|
||||
return clonedRoute{Route: route, root: root}
|
||||
return clonedRoute{Route: route, root: root, relative: ub.relative}
|
||||
}
|
||||
|
||||
type clonedRoute struct {
|
||||
*mux.Route
|
||||
root *url.URL
|
||||
root *url.URL
|
||||
relative bool
|
||||
}
|
||||
|
||||
func (cr clonedRoute) URL(pairs ...string) (*url.URL, error) {
|
||||
|
@ -208,6 +211,10 @@ func (cr clonedRoute) URL(pairs ...string) (*url.URL, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if cr.relative {
|
||||
return routeURL, nil
|
||||
}
|
||||
|
||||
if routeURL.Scheme == "" && routeURL.User == nil && routeURL.Host == "" {
|
||||
routeURL.Path = routeURL.Path[1:]
|
||||
}
|
||||
|
|
|
@ -92,25 +92,31 @@ func TestURLBuilder(t *testing.T) {
|
|||
"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()
|
||||
doTest := func(relative bool) {
|
||||
for _, root := range roots {
|
||||
urlBuilder, err := NewURLBuilderFromString(root, relative)
|
||||
if err != nil {
|
||||
t.Fatalf("%s: error building url: %v", testCase.description, err)
|
||||
t.Fatalf("unexpected error creating urlbuilder: %v", err)
|
||||
}
|
||||
|
||||
expectedURL := root + testCase.expectedPath
|
||||
for _, testCase := range makeURLBuilderTestCases(urlBuilder) {
|
||||
url, err := testCase.build()
|
||||
if err != nil {
|
||||
t.Fatalf("%s: error building url: %v", testCase.description, err)
|
||||
}
|
||||
expectedURL := testCase.expectedPath
|
||||
if !relative {
|
||||
expectedURL = root + expectedURL
|
||||
}
|
||||
|
||||
if url != expectedURL {
|
||||
t.Fatalf("%s: %q != %q", testCase.description, url, expectedURL)
|
||||
if url != expectedURL {
|
||||
t.Fatalf("%s: %q != %q", testCase.description, url, expectedURL)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
doTest(true)
|
||||
doTest(false)
|
||||
}
|
||||
|
||||
func TestURLBuilderWithPrefix(t *testing.T) {
|
||||
|
@ -121,25 +127,31 @@ func TestURLBuilderWithPrefix(t *testing.T) {
|
|||
"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()
|
||||
doTest := func(relative bool) {
|
||||
for _, root := range roots {
|
||||
urlBuilder, err := NewURLBuilderFromString(root, relative)
|
||||
if err != nil {
|
||||
t.Fatalf("%s: error building url: %v", testCase.description, err)
|
||||
t.Fatalf("unexpected error creating urlbuilder: %v", err)
|
||||
}
|
||||
|
||||
expectedURL := root[0:len(root)-1] + testCase.expectedPath
|
||||
for _, testCase := range makeURLBuilderTestCases(urlBuilder) {
|
||||
url, err := testCase.build()
|
||||
if err != nil {
|
||||
t.Fatalf("%s: error building url: %v", testCase.description, err)
|
||||
}
|
||||
|
||||
if url != expectedURL {
|
||||
t.Fatalf("%s: %q != %q", testCase.description, url, expectedURL)
|
||||
expectedURL := testCase.expectedPath
|
||||
if !relative {
|
||||
expectedURL = root[0:len(root)-1] + expectedURL
|
||||
}
|
||||
if url != expectedURL {
|
||||
t.Fatalf("%s: %q != %q", testCase.description, url, expectedURL)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
doTest(true)
|
||||
doTest(false)
|
||||
}
|
||||
|
||||
type builderFromRequestTestCase struct {
|
||||
|
@ -197,39 +209,48 @@ func TestBuilderFromRequest(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
|
||||
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
|
||||
doTest := func(relative bool) {
|
||||
for _, tr := range testRequests {
|
||||
var builder *URLBuilder
|
||||
if tr.configHost.Scheme != "" && tr.configHost.Host != "" {
|
||||
builder = NewURLBuilder(&tr.configHost, relative)
|
||||
} else {
|
||||
urlBase, err := url.Parse(tr.base)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
urlBase.Scheme = proto[0]
|
||||
expectedURL = urlBase.String() + testCase.expectedPath
|
||||
builder = NewURLBuilderFromRequest(tr.request, relative)
|
||||
}
|
||||
|
||||
if buildURL != expectedURL {
|
||||
t.Fatalf("%s: %q != %q", testCase.description, buildURL, expectedURL)
|
||||
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 = testCase.expectedPath
|
||||
if !relative {
|
||||
expectedURL = tr.base + expectedURL
|
||||
}
|
||||
} else {
|
||||
urlBase, err := url.Parse(tr.base)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
urlBase.Scheme = proto[0]
|
||||
expectedURL = testCase.expectedPath
|
||||
if !relative {
|
||||
expectedURL = urlBase.String() + expectedURL
|
||||
}
|
||||
}
|
||||
|
||||
if buildURL != expectedURL {
|
||||
t.Fatalf("%s: %q != %q", testCase.description, buildURL, expectedURL)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
doTest(true)
|
||||
doTest(false)
|
||||
}
|
||||
|
||||
func TestBuilderFromRequestWithPrefix(t *testing.T) {
|
||||
|
@ -270,12 +291,13 @@ func TestBuilderFromRequestWithPrefix(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
var relative bool
|
||||
for _, tr := range testRequests {
|
||||
var builder *URLBuilder
|
||||
if tr.configHost.Scheme != "" && tr.configHost.Host != "" {
|
||||
builder = NewURLBuilder(&tr.configHost)
|
||||
builder = NewURLBuilder(&tr.configHost, false)
|
||||
} else {
|
||||
builder = NewURLBuilderFromRequest(tr.request)
|
||||
builder = NewURLBuilderFromRequest(tr.request, false)
|
||||
}
|
||||
|
||||
for _, testCase := range makeURLBuilderTestCases(builder) {
|
||||
|
@ -283,17 +305,25 @@ func TestBuilderFromRequestWithPrefix(t *testing.T) {
|
|||
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
|
||||
expectedURL = testCase.expectedPath
|
||||
if !relative {
|
||||
expectedURL = tr.base[0:len(tr.base)-1] + expectedURL
|
||||
}
|
||||
} 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
|
||||
expectedURL = testCase.expectedPath
|
||||
if !relative {
|
||||
expectedURL = urlBase.String()[0:len(urlBase.String())-1] + expectedURL
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if buildURL != expectedURL {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue