gorilla/schema

[bug] Unstable decoding of different keys that are case-folded to the same value

yurykabanov opened this issue · 1 comments

Describe the bug
Having query with two distinct parameters, that are different in case (e.g. "x" and "X"), decoding returns unstable result - either one or another value will be present in result.

For example: for URL http://domain.tld/?x=aaa&X=bbb, decoder will return bbb in ~87% of cases and aaa in ~13% of cases. The percentage heavily depends on amount of query parameters and their complexity.

Versions
Go version: go version
go version go1.17.6 windows/amd64
package version: run git rev-parse HEAD inside the repo
github.com/gorilla/schema v1.2.0

Steps to Reproduce
The bug is triggered by trying to decode URL parameters with two distinct keys, that are case-folded to the same value.

Expected behavior
RFC 7230 claims that all components that are not scheme and host should be compared in a case-sensitive manner.
I understand that case insensitive comparison might be intended behavior for this library, but it should be stable (i.e. always return the same results for the exact same query). I assume this behavior is a result of randomized iteration order of maps.

Code Snippets

package main

import (
	"fmt"
	"net/url"

	"github.com/gorilla/schema"
)

func main() {
	decoder := schema.NewDecoder()

	s := `http://domain.tld/?x=a&X=b`
	u, _ := url.Parse(s)

	q := u.Query()

	fmt.Printf("%+v\n", q)

	stats := make(map[string]uint)
	for i := 0; i < 1000; i++ {
		var v struct {
			X string `schema:"x"`
		}
		_ = decoder.Decode(&v, q)
		stats[v.X] += 1
	}

	for k, v := range stats {
		fmt.Printf("%4d    %s\n", v, k)
	}
}

Result:

map[X:[b] x:[a]]  <-- `url.ParseQuery()` treats parameters as distinct ones
 866    b
 134    a

Expected result (case insensitive):

1000    b
OR
1000    a

Alternatively, following RFC 7230, having case-sensitive results could have been an option, but it will be a breaking change and it will definitely affect library users.

stale commented

This issue has been automatically marked as stale because it hasn't seen a recent update. It'll be automatically closed in a few days.