diff options
author | David Symonds <dsymonds@golang.org> | 2009-06-19 18:02:15 -0700 |
---|---|---|
committer | David Symonds <dsymonds@golang.org> | 2009-06-19 18:02:15 -0700 |
commit | dd5f6ae3ff81db61370b4d13fd03ae46b0bc23da (patch) | |
tree | 34122e885de1f52639d8f075648ddac26fd737af /src | |
parent | d22be483e5d12cf6d4a90c05f90a93f31c7764da (diff) | |
download | golang-dd5f6ae3ff81db61370b4d13fd03ae46b0bc23da.tar.gz |
Add form body parsing to http.Request.
better error handling throughout.
R=r,rsc
APPROVED=r
DELTA=254 (201 added, 3 deleted, 50 changed)
OCL=30515
CL=30545
Diffstat (limited to 'src')
-rw-r--r-- | src/pkg/Make.deps | 2 | ||||
-rw-r--r-- | src/pkg/http/request.go | 48 | ||||
-rw-r--r-- | src/pkg/http/request_test.go | 62 |
3 files changed, 111 insertions, 1 deletions
diff --git a/src/pkg/Make.deps b/src/pkg/Make.deps index eb99e558c..e70aebaad 100644 --- a/src/pkg/Make.deps +++ b/src/pkg/Make.deps @@ -25,7 +25,7 @@ go/token.install: strconv.install hash.install: io.install hash/adler32.install: hash.install os.install hash/crc32.install: hash.install os.install -http.install: bufio.install fmt.install io.install log.install net.install os.install path.install strconv.install strings.install utf8.install +http.install: bufio.install container/vector.install fmt.install io.install log.install net.install os.install path.install strconv.install strings.install utf8.install io.install: bytes.install os.install sync.install json.install: container/vector.install fmt.install io.install math.install reflect.install strconv.install strings.install utf8.install log.install: fmt.install io.install os.install runtime.install time.install diff --git a/src/pkg/http/request.go b/src/pkg/http/request.go index f8c37ec1e..5356f5525 100644 --- a/src/pkg/http/request.go +++ b/src/pkg/http/request.go @@ -11,6 +11,7 @@ package http import ( "bufio"; + "container/vector"; "fmt"; "http"; "io"; @@ -38,6 +39,7 @@ var ( BadHeader = &ProtocolError{"malformed http header"}; BadRequest = &ProtocolError{"invalid http request"}; BadHTTPVersion = &ProtocolError{"unsupported http version"}; + UnknownContentType = &ProtocolError{"unknown content type"}; ) // A Request represents a parsed HTTP request header. @@ -95,6 +97,10 @@ 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 + } // ProtoAtLeast returns whether the HTTP protocol used @@ -459,3 +465,45 @@ 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, "&") { + kvPair := strings.Split(kv, "="); + + var key, value string; + var e os.Error; + key, e = URLUnescape(kvPair[0]); + if e == nil && len(kvPair) > 1 { + value, e = URLUnescape(kvPair[1]); + } + if e != nil { + err := e; + } + + vec, ok := data[key]; + if !ok { + vec = vector.NewStringVector(0); + data[key] = vec; + } + vec.Push(value); + } + return +} + +// ParseForm parses the request body as a form. +func (r *Request) ParseForm() (err os.Error) { + 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 UnknownContentType +} diff --git a/src/pkg/http/request_test.go b/src/pkg/http/request_test.go new file mode 100644 index 000000000..ab611a0ca --- /dev/null +++ b/src/pkg/http/request_test.go @@ -0,0 +1,62 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package http + +import ( + "fmt"; + "http"; + "testing"; +) + +type stringMultimap map[string] []string + +type parseTest struct { + body string; + out stringMultimap; +} + +var parseTests = []parseTest{ + parseTest{ + body: "a=1&b=2", + out: stringMultimap{ "a": []string{ "1" }, "b": []string{ "2" } }, + }, + parseTest{ + body: "a=1&a=2&a=banana", + out: stringMultimap{ "a": []string{ "1", "2", "banana" } }, + }, + parseTest{ + body: "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); + 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); + } + for k, vs := range(test.out) { + vec, ok := data[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); + 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); + } + } + } + } +} |