-
Notifications
You must be signed in to change notification settings - Fork 18.3k
Description
I just saw CL https://go-review.googlesource.com/c/go/+/202237 by @bored-engineer (thank you Luke!) and was going to review and recommend/create a test for the CL creator.
The docs for http.Client.Do https://golang.org/pkg/net/http/#Client.Do promise that we'll always close the body even on errors and so far we missed a few spots on the trivial cases with minor oversight
Lines 469 to 495 in 72275c0
if isHTTP { | |
for k, vv := range req.Header { | |
if !httpguts.ValidHeaderFieldName(k) { | |
return nil, fmt.Errorf("net/http: invalid header field name %q", k) | |
} | |
for _, v := range vv { | |
if !httpguts.ValidHeaderFieldValue(v) { | |
return nil, fmt.Errorf("net/http: invalid header field value %q for key %v", v, k) | |
} | |
} | |
} | |
} | |
if t.useRegisteredProtocol(req) { | |
altProto, _ := t.altProto.Load().(map[string]RoundTripper) | |
if altRT := altProto[scheme]; altRT != nil { | |
if resp, err := altRT.RoundTrip(req); err != ErrSkipAltProtocol { | |
return resp, err | |
} | |
} | |
} | |
if !isHTTP { | |
req.closeBody() | |
return nil, &badStringError{"unsupported protocol scheme", scheme} | |
} | |
if req.Method != "" && !validMethod(req.Method) { | |
return nil, fmt.Errorf("net/http: invalid method %q", req.Method) |
that is:
a) if isHTTP {
b) if t.useRegisteredProtocol(req)
c) if req.Method != "" && !validMethod(req.Method) {
and I realize this is because that code has been modified piecemeal over the past decade.
This test is what we can use to bootstrap checks
package main
import (
"io"
"net/http"
"net/http/httptest"
"net/url"
"testing"
)
type bodyCloser bool
func (bc *bodyCloser) Close() error {
*bc = true
return nil
}
func (bc *bodyCloser) Read(b []byte) (n int, err error) {
return 0, io.EOF
}
func TestInvalidMethodClosesBody(t *testing.T) {
cst := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}))
defer cst.Close()
var bc bodyCloser
u, _ := url.Parse(cst.URL)
req := &http.Request{
Method: " ",
URL: u,
Body: &bc,
}
_, err := http.DefaultClient.Do(req)
if err == nil {
t.Fatal("Expected an error")
}
if !bc {
t.Fatal("Expected body to have been closed")
}
}
which currently gives
$ go test
--- FAIL: TestInvalidMethodClosesBody (0.00s)
it_test.go:39: Expected body to have been closed
This issue will be to send CLs to enforce those closes as well as tests so that we don't regress.