Skip to content

Commit

Permalink
url: handle ; in ParseQuery
Browse files Browse the repository at this point in the history
Most web frameworks allow ; as a synonym for &,
following a recommendation in some versions of
the HTML specification.  Do the same.

Remove overuse of Split.

Move ParseQuery tests from package http to package url.

Fixes #2210.

R=golang-dev, r
CC=golang-dev
https://golang.org/cl/4973062
  • Loading branch information
rsc committed Sep 6, 2011
1 parent 5ddf625 commit 686181e
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 67 deletions.
51 changes: 0 additions & 51 deletions src/pkg/http/request_test.go
Expand Up @@ -20,57 +20,6 @@ import (
"url"
)

type stringMultimap map[string][]string

type parseTest struct {
query string
out stringMultimap
}

var parseTests = []parseTest{
{
query: "a=1&b=2",
out: stringMultimap{"a": []string{"1"}, "b": []string{"2"}},
},
{
query: "a=1&a=2&a=banana",
out: stringMultimap{"a": []string{"1", "2", "banana"}},
},
{
query: "ascii=%3Ckey%3A+0x90%3E",
out: stringMultimap{"ascii": []string{"<key: 0x90>"}},
},
}

func TestParseForm(t *testing.T) {
for i, test := range parseTests {
form, err := url.ParseQuery(test.query)
if err != nil {
t.Errorf("test %d: Unexpected error: %v", i, err)
continue
}
if len(form) != len(test.out) {
t.Errorf("test %d: len(form) = %d, want %d", i, len(form), len(test.out))
}
for k, evs := range test.out {
vs, ok := form[k]
if !ok {
t.Errorf("test %d: Missing key %q", i, k)
continue
}
if len(vs) != len(evs) {
t.Errorf("test %d: len(form[%q]) = %d, want %d", i, k, len(vs), len(evs))
continue
}
for j, ev := range evs {
if v := vs[j]; v != ev {
t.Errorf("test %d: form[%q][%d] = %q, want %q", i, k, j, v, ev)
}
}
}
}
}

func TestQuery(t *testing.T) {
req := &Request{Method: "GET"}
req.URL, _ = url.Parse("http://www.google.com/search?q=foo&q=bar")
Expand Down
30 changes: 19 additions & 11 deletions src/pkg/url/url.go
Expand Up @@ -532,20 +532,28 @@ func ParseQuery(query string) (m Values, err os.Error) {
}

func parseQuery(m Values, query string) (err os.Error) {
for _, kv := range strings.Split(query, "&") {
if len(kv) == 0 {
for query != "" {
key := query
if i := strings.IndexAny(key, "&;"); i >= 0 {
key, query = key[:i], key[i+1:]
} else {
query = ""
}
if key == "" {
continue
}
kvPair := strings.SplitN(kv, "=", 2)

var key, value string
var e os.Error
key, e = QueryUnescape(kvPair[0])
if e == nil && len(kvPair) > 1 {
value, e = QueryUnescape(kvPair[1])
value := ""
if i := strings.Index(key, "="); i >= 0 {
key, value = key[:i], key[i+1:]
}
key, err1 := QueryUnescape(key)
if err1 != nil {
err = err1
continue
}
if e != nil {
err = e
value, err1 = QueryUnescape(value)
if err1 != nil {
err = err1
continue
}
m[key] = append(m[key], value)
Expand Down
62 changes: 57 additions & 5 deletions src/pkg/url/url_test.go
Expand Up @@ -11,11 +11,6 @@ import (
"testing"
)

// TODO(rsc):
// test Unescape
// test Escape
// test Parse

type URLTest struct {
in string
out *URL
Expand Down Expand Up @@ -696,3 +691,60 @@ func TestQueryValues(t *testing.T) {
t.Errorf("second Get(bar) = %q, want %q", g, e)
}
}

type parseTest struct {
query string
out Values
}

var parseTests = []parseTest{
{
query: "a=1&b=2",
out: Values{"a": []string{"1"}, "b": []string{"2"}},
},
{
query: "a=1&a=2&a=banana",
out: Values{"a": []string{"1", "2", "banana"}},
},
{
query: "ascii=%3Ckey%3A+0x90%3E",
out: Values{"ascii": []string{"<key: 0x90>"}},
},
{
query: "a=1;b=2",
out: Values{"a": []string{"1"}, "b": []string{"2"}},
},
{
query: "a=1&a=2;a=banana",
out: Values{"a": []string{"1", "2", "banana"}},
},
}

func TestParseQuery(t *testing.T) {
for i, test := range parseTests {
form, err := ParseQuery(test.query)
if err != nil {
t.Errorf("test %d: Unexpected error: %v", i, err)
continue
}
if len(form) != len(test.out) {
t.Errorf("test %d: len(form) = %d, want %d", i, len(form), len(test.out))
}
for k, evs := range test.out {
vs, ok := form[k]
if !ok {
t.Errorf("test %d: Missing key %q", i, k)
continue
}
if len(vs) != len(evs) {
t.Errorf("test %d: len(form[%q]) = %d, want %d", i, k, len(vs), len(evs))
continue
}
for j, ev := range evs {
if v := vs[j]; v != ev {
t.Errorf("test %d: form[%q][%d] = %q, want %q", i, k, j, v, ev)
}
}
}
}
}

0 comments on commit 686181e

Please sign in to comment.