From 25d4fa6ba8255fc00d40a5f99fa4098085578b51 Mon Sep 17 00:00:00 2001 From: Jordan Liggitt Date: Thu, 3 Apr 2025 12:51:46 -0400 Subject: [PATCH] Make Request#RequestURI honor configured context root Kubernetes-commit: 5677f7ab0b1b1ab22a71d01e4a710bf0f5e633aa --- openapi/client.go | 4 ++++ rest/request.go | 20 ++++++++++++-------- rest/request_test.go | 26 ++++++++++++++++++++++++-- 3 files changed, 40 insertions(+), 10 deletions(-) diff --git a/openapi/client.go b/openapi/client.go index 6a430571..d32895a2 100644 --- a/openapi/client.go +++ b/openapi/client.go @@ -56,9 +56,13 @@ func (c *client) Paths() (map[string]GroupVersion, error) { return nil, err } + // Calculate the client-side prefix for a "root" request + rootPrefix := strings.TrimSuffix(c.restClient.Get().AbsPath("/").URL().Path, "/") // Create GroupVersions for each element of the result result := map[string]GroupVersion{} for k, v := range discoMap.Paths { + // Trim off the prefix that will always be added in client-side + v.ServerRelativeURL = strings.TrimPrefix(v.ServerRelativeURL, rootPrefix) // If the server returned a URL rooted at /openapi/v3, preserve any additional client-side prefix. // If the server returned a URL not rooted at /openapi/v3, treat it as an actual server-relative URL. // See https://github.com/kubernetes/kubernetes/issues/117463 for details diff --git a/rest/request.go b/rest/request.go index 1eb2f9b4..9696d1cb 100644 --- a/rest/request.go +++ b/rest/request.go @@ -378,8 +378,9 @@ func (r *Request) NamespaceIfScoped(namespace string, scoped bool) *Request { return r } -// AbsPath overwrites an existing path with the segments provided. Trailing slashes are preserved -// when a single segment is passed. +// AbsPath overwrites an existing path with the segments provided. +// Trailing slashes are preserved when a single segment is passed. +// Any path in the request's REST client's base URL is preserved as a prefix. func (r *Request) AbsPath(segments ...string) *Request { if r.err != nil { return r @@ -392,8 +393,8 @@ func (r *Request) AbsPath(segments ...string) *Request { return r } -// RequestURI overwrites existing path and parameters with the value of the provided server relative -// URI. +// RequestURI overwrites existing path and parameters with the value of the provided server relative URI. +// This is equivalent to clearing params, then calling AbsPath() + Param() for each query parameter. func (r *Request) RequestURI(uri string) *Request { if r.err != nil { return r @@ -403,14 +404,17 @@ func (r *Request) RequestURI(uri string) *Request { r.err = err return r } - r.pathPrefix = locator.Path + // AbsPath handles prepending r.c.base.Path, if set + r.AbsPath(locator.Path) if len(locator.Query()) > 0 { - if r.params == nil { - r.params = make(url.Values) - } + // clear any existing params + r.params = make(url.Values) for k, v := range locator.Query() { r.params[k] = v } + } else { + // clear any existing params + r.params = nil } return r } diff --git a/rest/request_test.go b/rest/request_test.go index fd64dcb0..ad106169 100644 --- a/rest/request_test.go +++ b/rest/request_test.go @@ -292,14 +292,36 @@ func TestRequestError(t *testing.T) { } func TestRequestURI(t *testing.T) { - r := (&Request{}).Param("foo", "a") + r := (&Request{c: &RESTClient{base: &url.URL{Path: "/"}}}).Param("foo", "a").Param("bar", "b") r.Prefix("other") r.RequestURI("/test?foo=b&a=b&c=1&c=2") if r.pathPrefix != "/test" { t.Errorf("path is wrong: %#v", r) } if !reflect.DeepEqual(r.params, url.Values{"a": []string{"b"}, "foo": []string{"b"}, "c": []string{"1", "2"}}) { - t.Errorf("should have set a param: %#v", r) + t.Errorf("should have set a param, got: %#v", r.params) + } +} + +func TestRequestURIContext(t *testing.T) { + r := (&Request{c: &RESTClient{base: &url.URL{Path: "/context"}}}).Param("foo", "a").Param("bar", "b") + r.Prefix("other") + r.RequestURI("/test?foo=b&a=b&c=1&c=2") + if r.pathPrefix != "/context/test" { + t.Errorf("path is wrong: %#v", r) + } + if !reflect.DeepEqual(r.params, url.Values{"a": []string{"b"}, "foo": []string{"b"}, "c": []string{"1", "2"}}) { + t.Errorf("should have set a param, got: %#v", r.params) + } + + r = (&Request{c: &RESTClient{base: &url.URL{Path: "/context"}}}).Param("foo", "a").Param("bar", "b") + r.Prefix("other") + r.RequestURI("../test?foo=b&a=b&c=1&c=2") + if r.pathPrefix != "/test" { + t.Errorf("path is wrong: %#v", r) + } + if !reflect.DeepEqual(r.params, url.Values{"a": []string{"b"}, "foo": []string{"b"}, "c": []string{"1", "2"}}) { + t.Errorf("should have set a param, got: %#v", r.params) } }