return send(&req)
}
+// TODO: remove this function when PostForm takes a multimap.
func urlencode(data map[string]string) (b *bytes.Buffer) {
- b = new(bytes.Buffer)
- first := true
+ m := make(map[string][]string, len(data))
for k, v := range data {
- if first {
- first = false
- } else {
- b.WriteByte('&')
- }
- b.WriteString(URLEscape(k))
- b.WriteByte('=')
- b.WriteString(URLEscape(v))
+ m[k] = []string{v}
}
- return
+ return bytes.NewBuffer([]byte(EncodeQuery(m)))
}
// Head issues a HEAD to the specified URL.
}
return result
}
+
+// EncodeQuery encodes the query represented as a multimap.
+func EncodeQuery(m map[string][]string) string {
+ parts := make([]string, 0, len(m)) // will be large enough for most uses
+ for k, vs := range m {
+ prefix := URLEscape(k) + "="
+ for _, v := range vs {
+ parts = append(parts, prefix+URLEscape(v))
+ }
+ }
+ return strings.Join(parts, "&")
+}
}
}
}
+
+type qMap map[string][]string
+
+type EncodeQueryTest struct {
+ m qMap
+ expected string
+}
+
+var encodeQueryTests = []EncodeQueryTest{
+ {nil, ""},
+ {qMap{"q": {"puppies"}, "oe": {"utf8"}}, "q=puppies&oe=utf8"},
+ {qMap{"q": {"dogs", "&", "7"}}, "q=dogs&q=%26&q=7"},
+}
+
+func TestEncodeQuery(t *testing.T) {
+ for _, tt := range encodeQueryTests {
+ if q := EncodeQuery(tt.m); q != tt.expected {
+ t.Errorf(`EncodeQuery(%+v) = %q, want %q`, tt.m, q, tt.expected)
+ }
+ }
+}