Commit 686181ed authored by Russ Cox's avatar Russ Cox

url: handle ; in ParseQuery

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
parent 5ddf6255
......@@ -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")
......
......@@ -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)
......
......@@ -11,11 +11,6 @@ import (
"testing"
)
// TODO(rsc):
// test Unescape
// test Escape
// test Parse
type URLTest struct {
in string
out *URL
......@@ -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)
}
}
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment