diff --git a/pkg/client/request.go b/pkg/client/request.go index dd6ba4df0e4..e0d2f08272e 100644 --- a/pkg/client/request.go +++ b/pkg/client/request.go @@ -455,7 +455,8 @@ func (r *Request) Body(obj interface{}) *Request { return r } -func (r *Request) finalURL() string { +// URL returns the current working URL. +func (r *Request) URL() *url.URL { p := r.path if r.namespaceSet && !r.namespaceInQuery && len(r.namespace) > 0 { p = path.Join(p, "namespaces", r.namespace) @@ -472,9 +473,9 @@ func (r *Request) finalURL() string { p = path.Join(p, r.resourceName, r.subresource, r.subpath) } - finalURL := url.URL{} + finalURL := &url.URL{} if r.baseURL != nil { - finalURL = *r.baseURL + *finalURL = *r.baseURL } finalURL.Path = p @@ -494,16 +495,16 @@ func (r *Request) finalURL() string { query.Set("timeout", r.timeout.String()) } finalURL.RawQuery = query.Encode() - return finalURL.String() + return finalURL } -// Similar to finalURL(), but if the request contains name of an object +// finalURLTemplate is similar to URL(), but if the request contains name of an object // (e.g. GET for a specific Pod) it will be substited with "". -func (r Request) finalURLTemplate() string { +func (r *Request) finalURLTemplate() string { if len(r.resourceName) != 0 { r.resourceName = "" } - return r.finalURL() + return r.URL().String() } // Watch attempts to begin watching the requested location. @@ -512,7 +513,8 @@ func (r *Request) Watch() (watch.Interface, error) { if r.err != nil { return nil, r.err } - req, err := http.NewRequest(r.verb, r.finalURL(), r.body) + url := r.URL().String() + req, err := http.NewRequest(r.verb, url, r.body) if err != nil { return nil, err } @@ -533,7 +535,7 @@ func (r *Request) Watch() (watch.Interface, error) { if result := r.transformResponse(resp, req); result.err != nil { return nil, result.err } - return nil, fmt.Errorf("for request '%+v', got status: %v", req.URL, resp.StatusCode) + return nil, fmt.Errorf("for request '%+v', got status: %v", url, resp.StatusCode) } return watch.NewStreamWatcher(watchjson.NewDecoder(resp.Body, r.codec)), nil } @@ -546,7 +548,8 @@ func (r *Request) Stream() (io.ReadCloser, error) { if r.err != nil { return nil, r.err } - req, err := http.NewRequest(r.verb, r.finalURL(), nil) + url := r.URL().String() + req, err := http.NewRequest(r.verb, url, nil) if err != nil { return nil, err } @@ -567,7 +570,7 @@ func (r *Request) Stream() (io.ReadCloser, error) { // we have a decent shot at taking the object returned, parsing it as a status object and returning a more normal error bodyBytes, err := ioutil.ReadAll(resp.Body) if err != nil { - return nil, fmt.Errorf("%v while accessing %v", resp.Status, r.finalURL()) + return nil, fmt.Errorf("%v while accessing %v", resp.Status, url) } if runtimeObject, err := r.codec.Decode(bodyBytes); err == nil { @@ -579,7 +582,7 @@ func (r *Request) Stream() (io.ReadCloser, error) { } bodyText := string(bodyBytes) - return nil, fmt.Errorf("%s while accessing %v: %s", resp.Status, r.finalURL(), bodyText) + return nil, fmt.Errorf("%s while accessing %v: %s", resp.Status, url, bodyText) } return resp.Body, nil @@ -606,7 +609,7 @@ func (r *Request) Upgrade(config *Config, newRoundTripperFunc func(*tls.Config) r.client = &http.Client{Transport: wrapper} - req, err := http.NewRequest(r.verb, r.finalURL(), nil) + req, err := http.NewRequest(r.verb, r.URL().String(), nil) if err != nil { return nil, fmt.Errorf("Error creating request: %s", err) } @@ -647,8 +650,8 @@ func (r *Request) request(fn func(*http.Request, *http.Response)) error { maxRetries := 10 retries := 0 for { - url := r.finalURL() - req, err := http.NewRequest(r.verb, r.finalURL(), r.body) + url := r.URL().String() + req, err := http.NewRequest(r.verb, url, r.body) if err != nil { return err } diff --git a/pkg/client/request_test.go b/pkg/client/request_test.go index 4c5e7734bd0..cf8717a0942 100644 --- a/pkg/client/request_test.go +++ b/pkg/client/request_test.go @@ -71,26 +71,26 @@ func TestRequestWithErrorWontChange(t *testing.T) { func TestRequestPreservesBaseTrailingSlash(t *testing.T) { r := &Request{baseURL: &url.URL{}, path: "/path/", namespaceInQuery: true} - if s := r.finalURL(); s != "/path/" { + if s := r.URL().String(); s != "/path/" { t.Errorf("trailing slash should be preserved: %s", s) } } func TestRequestAbsPathPreservesTrailingSlash(t *testing.T) { r := (&Request{baseURL: &url.URL{}, namespaceInQuery: true}).AbsPath("/foo/") - if s := r.finalURL(); s != "/foo/" { + if s := r.URL().String(); s != "/foo/" { t.Errorf("trailing slash should be preserved: %s", s) } r = (&Request{baseURL: &url.URL{}}).AbsPath("/foo/") - if s := r.finalURL(); s != "/foo/" { + if s := r.URL().String(); s != "/foo/" { t.Errorf("trailing slash should be preserved: %s", s) } } func TestRequestAbsPathJoins(t *testing.T) { r := (&Request{baseURL: &url.URL{}, namespaceInQuery: true}).AbsPath("foo/bar", "baz") - if s := r.finalURL(); s != "foo/bar/baz" { + if s := r.URL().String(); s != "foo/bar/baz" { t.Errorf("trailing slash should be preserved: %s", s) } } @@ -105,7 +105,7 @@ func TestRequestSetsNamespace(t *testing.T) { if r.namespace == "" { t.Errorf("namespace should be set: %#v", r) } - if s := r.finalURL(); s != "?namespace=foo" { + if s := r.URL().String(); s != "?namespace=foo" { t.Errorf("namespace should be in params: %s", s) } @@ -114,7 +114,7 @@ func TestRequestSetsNamespace(t *testing.T) { Path: "/", }, }).Namespace("foo") - if s := r.finalURL(); s != "namespaces/foo" { + if s := r.URL().String(); s != "namespaces/foo" { t.Errorf("namespace should be in path: %s", s) } } @@ -124,7 +124,7 @@ func TestRequestOrdersNamespaceInPath(t *testing.T) { baseURL: &url.URL{}, path: "/test/", }).Name("bar").Resource("baz").Namespace("foo") - if s := r.finalURL(); s != "/test/namespaces/foo/baz/bar" { + if s := r.URL().String(); s != "/test/namespaces/foo/baz/bar" { t.Errorf("namespace should be in order in path: %s", s) } } @@ -134,7 +134,7 @@ func TestRequestOrdersSubResource(t *testing.T) { baseURL: &url.URL{}, path: "/test/", }).Name("bar").Resource("baz").Namespace("foo").Suffix("test").SubResource("a", "b") - if s := r.finalURL(); s != "/test/namespaces/foo/baz/bar/a/b/test" { + if s := r.URL().String(); s != "/test/namespaces/foo/baz/bar/a/b/test" { t.Errorf("namespace should be in order in path: %s", s) } } @@ -1028,7 +1028,7 @@ func TestUintParam(t *testing.T) { for _, item := range table { c := NewOrDie(&Config{}) r := c.Get().AbsPath("").UintParam(item.name, item.testVal) - if e, a := item.expectStr, r.finalURL(); e != a { + if e, a := item.expectStr, r.URL().String(); e != a { t.Errorf("expected %v, got %v", e, a) } }