Ensure query strings are escaped properly; fixes #324
diff --git a/params.go b/params.go
index 68c17eb..a980903 100644
--- a/params.go
+++ b/params.go
@@ -103,7 +103,8 @@
optsType = optsType.Elem()
}
- var optsSlice []string
+ params := url.Values{}
+
if optsValue.Kind() == reflect.Struct {
for i := 0; i < optsValue.NumField(); i++ {
v := optsValue.Field(i)
@@ -118,11 +119,11 @@
if !isZero(v) {
switch v.Kind() {
case reflect.String:
- optsSlice = append(optsSlice, tags[0]+"="+v.String())
+ params.Add(tags[0], v.String())
case reflect.Int:
- optsSlice = append(optsSlice, tags[0]+"="+strconv.FormatInt(v.Int(), 10))
+ params.Add(tags[0], strconv.FormatInt(v.Int(), 10))
case reflect.Bool:
- optsSlice = append(optsSlice, tags[0]+"="+strconv.FormatBool(v.Bool()))
+ params.Add(tags[0], strconv.FormatBool(v.Bool()))
}
} else {
// Otherwise, the field is not set.
@@ -132,18 +133,9 @@
}
}
}
+ }
- }
- // URL encode the string for safety.
- s := strings.Join(optsSlice, "&")
- if s != "" {
- s = "?" + s
- }
- u, err := url.Parse(s)
- if err != nil {
- return nil, err
- }
- return u, nil
+ return &url.URL{RawQuery: params.Encode()}, nil
}
// Return an error if the underlying type of 'opts' isn't a struct.
return nil, fmt.Errorf("Options type is not a struct.")
diff --git a/params_test.go b/params_test.go
index 9f1d3bd..4a2c9fe 100644
--- a/params_test.go
+++ b/params_test.go
@@ -43,7 +43,7 @@
R: "red",
C: true,
}
- expected := &url.URL{RawQuery: "j=2&r=red&c=true"}
+ expected := &url.URL{RawQuery: "c=true&j=2&r=red"}
actual, err := BuildQueryString(&opts)
if err != nil {
t.Errorf("Error building query string: %v", err)
@@ -138,5 +138,18 @@
expected = false
actual = isZero(testStructValue)
th.CheckEquals(t, expected, actual)
+}
+func TestQueriesAreEscaped(t *testing.T) {
+ type foo struct {
+ Name string `q:"something"`
+ Shape string `q:"else"`
+ }
+
+ expected := &url.URL{RawQuery: "else=Triangl+e&something=blah%2B%3F%21%21foo"}
+
+ actual, err := BuildQueryString(foo{Name: "blah+?!!foo", Shape: "Triangl e"})
+ th.AssertNoErr(t, err)
+
+ th.AssertDeepEquals(t, expected, actual)
}