diff options
author | David Symonds <dsymonds@golang.org> | 2009-06-25 21:05:44 -0700 |
---|---|---|
committer | David Symonds <dsymonds@golang.org> | 2009-06-25 21:05:44 -0700 |
commit | 3de312260ffcfe3b78885b5a8056d663c1c8d3bd (patch) | |
tree | 2cc44ada249886be2f0dd9708b5c556122cfc885 /src/pkg/http/request.go | |
parent | 3bcbb610293bec97cd2ae3ac8f575ff756bb8271 (diff) | |
download | golang-3de312260ffcfe3b78885b5a8056d663c1c8d3bd.tar.gz |
http Request parsing, plus a convenient accessor.
R=rsc
APPROVED=rsc
DELTA=95 (40 added, 14 deleted, 41 changed)
OCL=30727
CL=30784
Diffstat (limited to 'src/pkg/http/request.go')
-rw-r--r-- | src/pkg/http/request.go | 78 |
1 files changed, 54 insertions, 24 deletions
diff --git a/src/pkg/http/request.go b/src/pkg/http/request.go index 86b37d4c8..ef6dbe673 100644 --- a/src/pkg/http/request.go +++ b/src/pkg/http/request.go @@ -103,8 +103,8 @@ type Request struct { // 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; } @@ -581,9 +581,9 @@ func ReadRequest(b *bufio.Reader) (req *Request, err os.Error) { 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; @@ -593,7 +593,7 @@ func parseForm(body string) (data map[string] *vector.StringVector, err os.Error value, e = URLUnescape(kvPair[1]); } if e != nil { - err := e; + err = e; } vec, ok := data[key]; @@ -603,26 +603,56 @@ func parseForm(body string) (data map[string] *vector.StringVector, err os.Error } 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 "" } |