Commit 7c9c4fc3 authored by Brad Fitzpatrick's avatar Brad Fitzpatrick

http: fix hanging bug with HEAD responses

The transport readLoop was waiting forever for the client to
read the non-existent body before proceeding to read the next
request.

R=rsc
CC=golang-dev
https://golang.org/cl/4357051
parent 2be13a80
...@@ -436,11 +436,12 @@ func (pc *persistConn) readLoop() { ...@@ -436,11 +436,12 @@ func (pc *persistConn) readLoop() {
} else if err != nil { } else if err != nil {
alive = false alive = false
} }
hasBody := resp != nil && resp.ContentLength != 0
rc.ch <- responseAndError{resp, err} rc.ch <- responseAndError{resp, err}
// Wait for the just-returned response body to be fully consumed // Wait for the just-returned response body to be fully consumed
// before we race and peek on the underlying bufio reader. // before we race and peek on the underlying bufio reader.
if alive { if alive && hasBody {
<-resp.Body.(*bodyEOFSignal).ch <-resp.Body.(*bodyEOFSignal).ch
} }
} }
...@@ -512,7 +513,7 @@ func responseIsKeepAlive(res *Response) bool { ...@@ -512,7 +513,7 @@ func responseIsKeepAlive(res *Response) bool {
// the response body with a bodyEOFSignal-wrapped version. // the response body with a bodyEOFSignal-wrapped version.
func readResponseWithEOFSignal(r *bufio.Reader, requestMethod string) (resp *Response, err os.Error) { func readResponseWithEOFSignal(r *bufio.Reader, requestMethod string) (resp *Response, err os.Error) {
resp, err = ReadResponse(r, requestMethod) resp, err = ReadResponse(r, requestMethod)
if err == nil { if err == nil && resp.ContentLength != 0 {
resp.Body = &bodyEOFSignal{resp.Body, make(chan bool, 1), false} resp.Body = &bodyEOFSignal{resp.Body, make(chan bool, 1), false}
} }
return return
......
...@@ -261,6 +261,34 @@ func TestTransportServerClosingUnexpectedly(t *testing.T) { ...@@ -261,6 +261,34 @@ func TestTransportServerClosingUnexpectedly(t *testing.T) {
} }
} }
// TestTransportHeadResponses verifies that we deal with Content-Lengths
// with no bodies properly
func TestTransportHeadResponses(t *testing.T) {
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
if r.Method != "HEAD" {
panic("expected HEAD; got " + r.Method)
}
w.Header().Set("Content-Length", "123")
w.WriteHeader(200)
}))
defer ts.Close()
tr := &Transport{DisableKeepAlives: false}
c := &Client{Transport: tr}
for i := 0; i < 2; i++ {
res, err := c.Head(ts.URL)
if err != nil {
t.Errorf("error on loop %d: %v", i, err)
}
if e, g := "123", res.Header.Get("Content-Length"); e != g {
t.Errorf("loop %d: expected Content-Length header of %q, got %q", e, g)
}
if e, g := int64(0), res.ContentLength; e != g {
t.Errorf("loop %d: expected res.ContentLength of %v, got %v", e, g)
}
}
}
func TestTransportNilURL(t *testing.T) { func TestTransportNilURL(t *testing.T) {
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
fmt.Fprintf(w, "Hi") fmt.Fprintf(w, "Hi")
......
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