This is an automated email from the ASF dual-hosted git repository. marsevilspirit pushed a commit to branch develop in repository https://gitbox.apache.org/repos/asf/dubbo-go.git
The following commit(s) were added to refs/heads/develop by this push: new ce295e4a4 fix: URL parameter loss issue in SetParams method (#3022) ce295e4a4 is described below commit ce295e4a468583051564251b556439ef7ca52b08 Author: CAICAII <39020005+caica...@users.noreply.github.com> AuthorDate: Thu Sep 18 12:32:31 2025 +0800 fix: URL parameter loss issue in SetParams method (#3022) --- common/url.go | 19 +++++++++++++++---- common/url_test.go | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/common/url.go b/common/url.go index 09474729c..af6e68b08 100644 --- a/common/url.go +++ b/common/url.go @@ -737,13 +737,24 @@ func (c *URL) GetMethodParamBool(method string, key string, d bool) bool { return r } -// SetParams will put all key-value pair into URL. +// SetParams copies all key-value pairs into URL. // 1. if there already has same key, the value will be override -// 2. it's not thread safe +// 2. this method acquires a write lock and deep-copies the provided values to avoid data races // 3. think twice when you want to invoke this method func (c *URL) SetParams(m url.Values) { - for k := range m { - c.SetParam(k, m.Get(k)) + c.paramsLock.Lock() + defer c.paramsLock.Unlock() + if c.params == nil { + c.params = url.Values{} + } + for k, vs := range m { + if len(vs) == 0 { + delete(c.params, k) + continue + } + copied := make([]string, len(vs)) + copy(copied, vs) + c.params[k] = copied } } diff --git a/common/url_test.go b/common/url_test.go index 91880c266..5ee5197e2 100644 --- a/common/url_test.go +++ b/common/url_test.go @@ -592,3 +592,38 @@ func TestNewURLWithMultiAddr(t *testing.T) { assert.Nil(t, err) assert.Equal(t, "127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183", u4.Location) } + +func TestURLSetParamsMultiValue(t *testing.T) { + // Test case to verify multi-value parameter handling + u := &URL{} + + // Create url.Values with multiple values for the same key + params := url.Values{} + params.Add("tag", "foo") + params.Add("tag", "bar") + params.Add("tag", "baz") + params.Set("single", "value") + + // Set the parameters using the fixed implementation + u.SetParams(params) + + // The implementation should preserve all values (multi-values stored internally) + got := u.GetParams()["tag"] + assert.ElementsMatch(t, []string{"foo", "bar", "baz"}, got) + assert.Equal(t, "value", u.GetParam("single", "")) + + // Test with empty values + params2 := url.Values{} + params2.Add("empty", "") + params2.Add("empty", "value") + params2.Add("only_empty", "") + + u2 := &URL{} + u2.SetParams(params2) + + // Empty value slots are preserved as provided by caller + got2 := u2.GetParams()["empty"] + assert.ElementsMatch(t, []string{"", "value"}, got2) + got3 := u2.GetParams()["only_empty"] + assert.ElementsMatch(t, []string{""}, got3) +}