client/tailscale: fix Client.BuildURL and Client.BuildTailnetURL (#15064)
This method uses `path.Join` to build the URL. Turns out with 1.24 this started stripping consecutive "/" characters, so "http://..." in baseURL becomes "http:/...". Also, `c.Tailnet` is a function that returns `c.tailnet`. Using it as a path element would encode as a pointer instead of the tailnet name. Finally, provide a way to prevent escaping of path elements e.g. for `?` in `acl?details=1`. Updates #15015 Signed-off-by: Andrew Lytvynov <awly@tailscale.com>main
parent
836c01258d
commit
2c3338c46b
@ -0,0 +1,86 @@ |
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
package tailscale |
||||
|
||||
import ( |
||||
"net/url" |
||||
"testing" |
||||
) |
||||
|
||||
func TestClientBuildURL(t *testing.T) { |
||||
c := Client{BaseURL: "http://127.0.0.1:1234"} |
||||
for _, tt := range []struct { |
||||
desc string |
||||
elements []any |
||||
want string |
||||
}{ |
||||
{ |
||||
desc: "single-element", |
||||
elements: []any{"devices"}, |
||||
want: "http://127.0.0.1:1234/api/v2/devices", |
||||
}, |
||||
{ |
||||
desc: "multiple-elements", |
||||
elements: []any{"tailnet", "example.com"}, |
||||
want: "http://127.0.0.1:1234/api/v2/tailnet/example.com", |
||||
}, |
||||
{ |
||||
desc: "escape-element", |
||||
elements: []any{"tailnet", "example dot com?foo=bar"}, |
||||
want: `http://127.0.0.1:1234/api/v2/tailnet/example%20dot%20com%3Ffoo=bar`, |
||||
}, |
||||
{ |
||||
desc: "url.Values", |
||||
elements: []any{"tailnet", "example.com", "acl", url.Values{"details": {"1"}}}, |
||||
want: `http://127.0.0.1:1234/api/v2/tailnet/example.com/acl?details=1`, |
||||
}, |
||||
} { |
||||
t.Run(tt.desc, func(t *testing.T) { |
||||
got := c.BuildURL(tt.elements...) |
||||
if got != tt.want { |
||||
t.Errorf("got %q, want %q", got, tt.want) |
||||
} |
||||
}) |
||||
} |
||||
} |
||||
|
||||
func TestClientBuildTailnetURL(t *testing.T) { |
||||
c := Client{ |
||||
BaseURL: "http://127.0.0.1:1234", |
||||
tailnet: "example.com", |
||||
} |
||||
for _, tt := range []struct { |
||||
desc string |
||||
elements []any |
||||
want string |
||||
}{ |
||||
{ |
||||
desc: "single-element", |
||||
elements: []any{"devices"}, |
||||
want: "http://127.0.0.1:1234/api/v2/tailnet/example.com/devices", |
||||
}, |
||||
{ |
||||
desc: "multiple-elements", |
||||
elements: []any{"devices", 123}, |
||||
want: "http://127.0.0.1:1234/api/v2/tailnet/example.com/devices/123", |
||||
}, |
||||
{ |
||||
desc: "escape-element", |
||||
elements: []any{"foo bar?baz=qux"}, |
||||
want: `http://127.0.0.1:1234/api/v2/tailnet/example.com/foo%20bar%3Fbaz=qux`, |
||||
}, |
||||
{ |
||||
desc: "url.Values", |
||||
elements: []any{"acl", url.Values{"details": {"1"}}}, |
||||
want: `http://127.0.0.1:1234/api/v2/tailnet/example.com/acl?details=1`, |
||||
}, |
||||
} { |
||||
t.Run(tt.desc, func(t *testing.T) { |
||||
got := c.BuildTailnetURL(tt.elements...) |
||||
if got != tt.want { |
||||
t.Errorf("got %q, want %q", got, tt.want) |
||||
} |
||||
}) |
||||
} |
||||
} |
||||
Loading…
Reference in new issue