// The User-Agent: header string, if sent in the request.
UserAgent string;
- // The parsed form data. Only available after ParseForm is called.
- FormData map[string] *vector.StringVector
+ // The parsed form. Only available after ParseForm is called.
+ Form map[string] []string;
}
return req, nil
}
-func parseForm(body string) (data map[string] *vector.StringVector, err os.Error) {
- data = make(map[string] *vector.StringVector);
- for _, kv := range strings.Split(body, "&", 0) {
+func parseForm(query string) (m map[string] []string, err os.Error) {
+ data := make(map[string] *vector.StringVector);
+ for _, kv := range strings.Split(query, "&", 0) {
kvPair := strings.Split(kv, "=", 2);
var key, value string;
value, e = URLUnescape(kvPair[1]);
}
if e != nil {
- err := e;
+ err = e;
}
vec, ok := data[key];
}
vec.Push(value);
}
+
+ m = make(map[string] []string);
+ for k, vec := range data {
+ m[k] = vec.Data();
+ }
+
return
}
-// ParseForm parses the request body as a form.
-// TODO(dsymonds): Parse r.Url.RawQuery instead for GET requests.
+// ParseForm parses the request body as a form for POST requests, or the raw query for GET requests.
+// It is idempotent.
func (r *Request) ParseForm() (err os.Error) {
- if r.Body == nil {
- return os.ErrorString("missing form body");
- }
- ct, ok := r.Header["Content-Type"];
- if !ok {
- ct = "application/x-www-form-urlencoded"; // default
- }
- switch ct {
- case "text/plain", "application/x-www-form-urlencoded":
- buf := new(io.ByteBuffer);
- io.Copy(r.Body, buf);
- r.FormData, err = parseForm(string(buf.Data()));
- return err
- // TODO(dsymonds): Handle multipart/form-data
- }
- return &badStringError{"unknown Content-Type", ct};
+ if r.Form != nil {
+ return
+ }
+
+ var query string;
+
+ switch r.Method {
+ case "GET":
+ query = r.Url.RawQuery;
+ case "POST":
+ if r.Body == nil {
+ return os.ErrorString("missing form body")
+ }
+ ct, _ := r.Header["Content-Type"];
+ switch ct {
+ case "text/plain", "application/x-www-form-urlencoded", "":
+ var b []byte;
+ if b, err = io.ReadAll(r.Body); err != nil {
+ return
+ }
+ query = string(b);
+ // TODO(dsymonds): Handle multipart/form-data
+ default:
+ return &badStringError{"unknown Content-Type", ct}
+ }
+ }
+ r.Form, err = parseForm(query);
+ return
+}
+
+// FormValue returns the first value for the named component of the query.
+// FormValue calls ParseForm if necessary.
+func (r *Request) FormValue(key string) string {
+ if r.Form == nil {
+ r.ParseForm();
+ }
+ if vs, ok := r.Form[key]; ok && len(vs) > 0 {
+ return vs[0]
+ }
+ return ""
}
import (
"fmt";
"http";
+ "os";
"testing";
)
type stringMultimap map[string] []string
type parseTest struct {
- body string;
+ query string;
out stringMultimap;
}
var parseTests = []parseTest{
parseTest{
- body: "a=1&b=2",
+ query: "a=1&b=2",
out: stringMultimap{ "a": []string{ "1" }, "b": []string{ "2" } },
},
parseTest{
- body: "a=1&a=2&a=banana",
+ query: "a=1&a=2&a=banana",
out: stringMultimap{ "a": []string{ "1", "2", "banana" } },
},
parseTest{
- body: "ascii=%3Ckey%3A+0x90%3E",
+ query: "ascii=%3Ckey%3A+0x90%3E",
out: stringMultimap{ "ascii": []string{ "<key: 0x90>" } },
},
}
func TestParseForm(t *testing.T) {
for i, test := range parseTests {
- data, err := parseForm(test.body);
+ form, err := parseForm(test.query);
if err != nil {
t.Errorf("test %d: Unexpected error: %v", i, err);
continue
}
- if dlen, olen := len(data), len(test.out); dlen != olen {
- t.Errorf("test %d: Have %d keys, want %d keys", i, dlen, olen);
+ if len(form) != len(test.out) {
+ t.Errorf("test %d: len(form) = %d, want %d", i, len(form), len(test.out));
}
- for k, vs := range test.out {
- vec, ok := data[k];
+ for k, evs := range test.out {
+ vs, ok := form[k];
if !ok {
t.Errorf("test %d: Missing key %q", i, k);
continue
}
- if dlen, olen := vec.Len(), len(vs); dlen != olen {
- t.Errorf("test %d: key %q: Have %d keys, want %d keys", i, k, dlen, olen);
+ if len(vs) != len(evs) {
+ t.Errorf("test %d: len(form[%q]) = %d, want %d", i, k, len(vs), len(evs));
continue
}
- for j, v := range vs {
- if dv := vec.At(j); dv != v {
- t.Errorf("test %d: key %q: val %d: Have %q, want %q", i, k, j, dv, v);
+ 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) {
+ var err os.Error;
+ req := &Request{ Method: "GET" };
+ req.Url, err = ParseURL("http://www.google.com/search?q=foo&q=bar");
+ if q := req.FormValue("q"); q != "foo" {
+ t.Errorf(`req.FormValue("q") = %q, want "foo"`, q);
+ }
+}