From 686181edfed0f738fe6aafe76fafded9d0be155b Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 6 Sep 2011 12:24:24 -0400 Subject: [PATCH] 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 --- src/pkg/http/request_test.go | 51 ----------------------------- src/pkg/url/url.go | 30 ++++++++++------- src/pkg/url/url_test.go | 62 +++++++++++++++++++++++++++++++++--- 3 files changed, 76 insertions(+), 67 deletions(-) diff --git a/src/pkg/http/request_test.go b/src/pkg/http/request_test.go index 869cd57b696..175d6f170b8 100644 --- a/src/pkg/http/request_test.go +++ b/src/pkg/http/request_test.go @@ -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{""}}, - }, -} - -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") diff --git a/src/pkg/url/url.go b/src/pkg/url/url.go index d07b016118f..9d193482ce4 100644 --- a/src/pkg/url/url.go +++ b/src/pkg/url/url.go @@ -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:] } - if e != nil { - err = e + key, err1 := QueryUnescape(key) + if err1 != nil { + err = err1 + continue + } + value, err1 = QueryUnescape(value) + if err1 != nil { + err = err1 continue } m[key] = append(m[key], value) diff --git a/src/pkg/url/url_test.go b/src/pkg/url/url_test.go index af394d4fb4a..8c27e18e1aa 100644 --- a/src/pkg/url/url_test.go +++ b/src/pkg/url/url_test.go @@ -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{""}}, + }, + { + 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) + } + } + } + } +}