google / go-querystring

go-querystring is Go library for encoding structs into URL query strings.

Home Page:https://pkg.go.dev/github.com/google/go-querystring/query

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Non-nil pointer to slice not encoded properly

dmlittle opened this issue · comments

What
Pointers to non-nil values are not being encoded properly. The options are not being considered when encoding a pointer to a slice with the brackets options.

Sample Code
Below is a snippet that is able to reproduce the issue:

package main

import (
	"fmt"

	"github.com/google/go-querystring/query"
)

type Query struct {
	List []string `url:"list,omitempty,brackets"`
}

type QueryWithPointer struct {
	List *[]string `url:"list,omitempty,brackets"`
}

func main() {
	q1 := Query{List: []string{"value1", "value2"}}
	qs1, _ := query.Values(q1)

	q2 := QueryWithPointer{List: &[]string{"value1", "value2"}}
	qs2, _ := query.Values(q2)

	fmt.Println(qs1.Encode()) // list%5B%5D=value1&list%5B%5D=value2 <- CORRECT
	fmt.Println(qs2.Encode()) // list=%5Bvalue1+value2%5D <- INCORRECT. Output doesn't consider brackets option
}

I believe moving the pointer dereferencing check above the slice/array logic handler solves the issue. I'm happy to put up a PR if you think this is a valid solution!

Thanks, @dmlittle, for the report.

First off, I would recommend you carefully analyze why you are using *[]string in the first place since a slice is a reference type and can itself be nil.

Having said that, however, I see your point and it sounds to me like what you are proposing is a valid solution.

If you decide to go ahead with a PR and @willnorris does not object, just make sure you write your tests to cover as many cases as you can so that we hopefully don't break existing usage.

@gmlewis thanks for the recommendation; it makes perfect sense!

Although you should probably be using slices instead of creating pointers to arrays, the same bug currently exists for pointers to arrays (not slices) and I think that should definitely be fixed (?).

As for the PR, I'll wait to see what @willnorris thinks before writing the PR and additional test cases.

I'll be honest, it's been a really long time since I've done anything but trivial changes to this package, so don't completely remember some of my design ideas.

But it seems that the intent was that pointers to values encode the same as equivalent non-pointer values. I believe that's what

for sv.Kind() == reflect.Ptr {
if sv.IsNil() {
break
}
sv = sv.Elem()
}
is all about.

It looks like that block just needs to be moved before

if sv.Kind() == reflect.Slice || sv.Kind() == reflect.Array {
?
I honestly don't remember if there was a reason to the current order of that code. Try it and see if any of the tests break?

fixed in #42. Confirmed with @dmlittle's sample code in the original comment (thanks for the reproduction case, by the way... that was helpful)