maxFormSize = int64(10 << 20) // 10 MB is a lot of text.
reader = io.LimitReader(r.Body, maxFormSize+1)
}
- vs = make(url.Values)
- e := parsePostFormURLEncoded(vs, reader, maxFormSize)
+ b, e := ioutil.ReadAll(reader)
+ if e != nil {
+ if err == nil {
+ err = e
+ }
+ break
+ }
+ if int64(len(b)) > maxFormSize {
+ err = errors.New("http: POST too large")
+ return
+ }
+ vs, e = url.ParseQuery(string(b))
if err == nil {
err = e
}
return
}
-// parsePostFormURLEncoded reads from r, the reader of a POST form to populate vs which is a url-type values.
-// maxFormSize indicates the maximum number of bytes that will be read from r.
-func parsePostFormURLEncoded(vs url.Values, r io.Reader, maxFormSize int64) error {
- br := newBufioReader(r)
- defer putBufioReader(br)
-
- var readSize int64
- for {
- // Read next "key=value&" or "justkey&".
- // If this is the last pair, b will contain just "key=value" or "justkey".
- b, err := br.ReadBytes('&')
- if err != nil && err != io.EOF && err != bufio.ErrBufferFull {
- return err
- }
- isEOF := err == io.EOF
- readSize += int64(len(b))
- if readSize >= maxFormSize {
- return errors.New("http: POST too large")
- }
-
- // Remove last delimiter
- if len(b) > 0 && b[len(b)-1] == '&' {
- b = b[:len(b)-1]
- }
-
- // Parse key and value
- k := string(b)
- var v string
- if i := strings.Index(k, "="); i > -1 {
- k, v = k[:i], k[i+1:]
- }
- if k, err = url.QueryUnescape(k); err != nil {
- return err
- }
- if v, err = url.QueryUnescape(v); err != nil {
- return err
- }
-
- // Populate vs
- vs[k] = append(vs[k], v)
- if isEOF {
- return nil
- }
- }
-}
-
// ParseForm parses the raw query from the URL and updates r.Form.
//
// For POST or PUT requests, it also parses the request body as a form and
}
func TestPostQuery(t *testing.T) {
- req, _ := NewRequest("POST", "http://www.google.com/search?q=foo&q=bar&both=x&prio=1&empty=not&orphan=nope",
- strings.NewReader("z=post&both=y&prio=2&orphan&empty="))
+ req, _ := NewRequest("POST", "http://www.google.com/search?q=foo&q=bar&both=x&prio=1&empty=not",
+ strings.NewReader("z=post&both=y&prio=2&empty="))
req.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")
if q := req.FormValue("q"); q != "foo" {
if empty := req.FormValue("empty"); empty != "" {
t.Errorf(`req.FormValue("empty") = %q, want "" (from body)`, empty)
}
- if orphan := req.FormValue("orphan"); orphan != "" {
- t.Errorf(`req.FormValue("orphan") = %q, want "" (from body)`, orphan)
- }
-}
-
-func BenchmarkPostQuery(b *testing.B) {
- req, _ := NewRequest("POST", "http://www.google.com/search?q=foo&q=bar&both=x&prio=1&empty=not&orphan=nope",
- strings.NewReader("z=post&both=y&prio=2&orphan&empty="))
- req.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")
- b.ReportAllocs()
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- req.PostForm = nil
- req.ParseForm()
- }
}
func TestPatchQuery(t *testing.T) {
- req, _ := NewRequest("PATCH", "http://www.google.com/search?q=foo&q=bar&both=x&prio=1&empty=not&orphan=nope",
- strings.NewReader("z=post&both=y&prio=2&orphan&empty="))
+ req, _ := NewRequest("PATCH", "http://www.google.com/search?q=foo&q=bar&both=x&prio=1&empty=not",
+ strings.NewReader("z=post&both=y&prio=2&empty="))
req.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")
if q := req.FormValue("q"); q != "foo" {
if empty := req.FormValue("empty"); empty != "" {
t.Errorf(`req.FormValue("empty") = %q, want "" (from body)`, empty)
}
- if orphan := req.FormValue("orphan"); orphan != "" {
- t.Errorf(`req.FormValue("orphan") = %q, want "" (from body)`, orphan)
- }
}
type stringMap map[string][]string