Commit 56bcef02 authored by Brad Fitzpatrick's avatar Brad Fitzpatrick

net/http: add missing error checking reading trailers

This is a simplified version of earlier versions of this CL
and now only fixes obviously incorrect things, without
changing the locking on bodyEOFReader.

I'd like to see if this is sufficient before changing the
locking.

Update #4191

R=golang-dev, rsc, dave
CC=golang-dev
https://golang.org/cl/6739055
parent aa388017
...@@ -219,6 +219,9 @@ func TestRedirects(t *testing.T) { ...@@ -219,6 +219,9 @@ func TestRedirects(t *testing.T) {
return checkErr return checkErr
}} }}
res, err := c.Get(ts.URL) res, err := c.Get(ts.URL)
if err != nil {
t.Fatalf("Get error: %v", err)
}
finalUrl := res.Request.URL.String() finalUrl := res.Request.URL.String()
if e, g := "<nil>", fmt.Sprintf("%v", err); e != g { if e, g := "<nil>", fmt.Sprintf("%v", err); e != g {
t.Errorf("with custom client, expected error %q, got %q", e, g) t.Errorf("with custom client, expected error %q, got %q", e, g)
...@@ -335,7 +338,10 @@ func TestRedirectCookiesJar(t *testing.T) { ...@@ -335,7 +338,10 @@ func TestRedirectCookiesJar(t *testing.T) {
c.Jar = &TestJar{perURL: make(map[string][]*Cookie)} c.Jar = &TestJar{perURL: make(map[string][]*Cookie)}
u, _ := url.Parse(ts.URL) u, _ := url.Parse(ts.URL)
c.Jar.SetCookies(u, []*Cookie{expectedCookies[0]}) c.Jar.SetCookies(u, []*Cookie{expectedCookies[0]})
resp, _ := c.Get(ts.URL) resp, err := c.Get(ts.URL)
if err != nil {
t.Fatalf("Get: %v", err)
}
matchReturnedCookies(t, expectedCookies, resp.Cookies()) matchReturnedCookies(t, expectedCookies, resp.Cookies())
} }
......
...@@ -567,14 +567,22 @@ func seeUpcomingDoubleCRLF(r *bufio.Reader) bool { ...@@ -567,14 +567,22 @@ func seeUpcomingDoubleCRLF(r *bufio.Reader) bool {
return false return false
} }
var errTrailerEOF = errors.New("http: unexpected EOF reading trailer")
func (b *body) readTrailer() error { func (b *body) readTrailer() error {
// The common case, since nobody uses trailers. // The common case, since nobody uses trailers.
buf, _ := b.r.Peek(2) buf, err := b.r.Peek(2)
if bytes.Equal(buf, singleCRLF) { if bytes.Equal(buf, singleCRLF) {
b.r.ReadByte() b.r.ReadByte()
b.r.ReadByte() b.r.ReadByte()
return nil return nil
} }
if len(buf) < 2 {
return errTrailerEOF
}
if err != nil {
return err
}
// Make sure there's a header terminator coming up, to prevent // Make sure there's a header terminator coming up, to prevent
// a DoS with an unbounded size Trailer. It's not easy to // a DoS with an unbounded size Trailer. It's not easy to
...@@ -590,6 +598,9 @@ func (b *body) readTrailer() error { ...@@ -590,6 +598,9 @@ func (b *body) readTrailer() error {
hdr, err := textproto.NewReader(b.r).ReadMIMEHeader() hdr, err := textproto.NewReader(b.r).ReadMIMEHeader()
if err != nil { if err != nil {
if err == io.EOF {
return errTrailerEOF
}
return err return err
} }
switch rr := b.hdr.(type) { switch rr := b.hdr.(type) {
......
// Copyright 2012 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 (
"bufio"
"strings"
"testing"
)
func TestBodyReadBadTrailer(t *testing.T) {
b := &body{
Reader: strings.NewReader("foobar"),
hdr: true, // force reading the trailer
r: bufio.NewReader(strings.NewReader("")),
}
buf := make([]byte, 7)
n, err := b.Read(buf[:3])
got := string(buf[:n])
if got != "foo" || err != nil {
t.Fatalf(`first Read = %n (%q), %v; want 3 ("foo")`, n, got, err)
}
n, err = b.Read(buf[:])
got = string(buf[:n])
if got != "bar" || err != nil {
t.Fatalf(`second Read = %n (%q), %v; want 3 ("bar")`, n, got, err)
}
n, err = b.Read(buf[:])
got = string(buf[:n])
if err == nil {
t.Errorf("final Read was successful (%q), expected error from trailer read", got)
}
}
...@@ -605,6 +605,9 @@ func (pc *persistConn) readLoop() { ...@@ -605,6 +605,9 @@ func (pc *persistConn) readLoop() {
alive = false alive = false
} }
// TODO(bradfitz): this hasBody conflicts with the defition
// above which excludes HEAD requests. Is this one
// incomplete?
hasBody := resp != nil && resp.ContentLength != 0 hasBody := resp != nil && resp.ContentLength != 0
var waitForBodyRead chan bool var waitForBodyRead chan bool
if hasBody { if hasBody {
...@@ -806,11 +809,6 @@ func canonicalAddr(url *url.URL) string { ...@@ -806,11 +809,6 @@ func canonicalAddr(url *url.URL) string {
return addr return addr
} }
func responseIsKeepAlive(res *Response) bool {
// TODO: implement. for now just always shutting down the connection.
return false
}
// bodyEOFSignal wraps a ReadCloser but runs fn (if non-nil) at most // bodyEOFSignal wraps a ReadCloser but runs fn (if non-nil) at most
// once, right before the final Read() or Close() call returns, but after // once, right before the final Read() or Close() call returns, but after
// EOF has been seen. // EOF has been seen.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment