Commit b2b15d12 authored by Brad Fitzpatrick's avatar Brad Fitzpatrick

net/http: document and test Client.Post treating Reader body as ReadCloser

R=golang-dev, r
CC=golang-dev
https://golang.org/cl/11542044
parent bc31bccc
...@@ -74,8 +74,8 @@ type RoundTripper interface { ...@@ -74,8 +74,8 @@ type RoundTripper interface {
// authentication, or cookies. // authentication, or cookies.
// //
// RoundTrip should not modify the request, except for // RoundTrip should not modify the request, except for
// consuming the Body. The request's URL and Header fields // consuming and closing the Body. The request's URL and
// are guaranteed to be initialized. // Header fields are guaranteed to be initialized.
RoundTrip(*Request) (*Response, error) RoundTrip(*Request) (*Response, error)
} }
...@@ -346,6 +346,9 @@ func Post(url string, bodyType string, body io.Reader) (resp *Response, err erro ...@@ -346,6 +346,9 @@ func Post(url string, bodyType string, body io.Reader) (resp *Response, err erro
// Post issues a POST to the specified URL. // Post issues a POST to the specified URL.
// //
// Caller should close resp.Body when done reading from it. // Caller should close resp.Body when done reading from it.
//
// If the provided body is also an io.Closer, it is closed after the
// body is successfully written to the server.
func (c *Client) Post(url string, bodyType string, body io.Reader) (resp *Response, err error) { func (c *Client) Post(url string, bodyType string, body io.Reader) (resp *Response, err error) {
req, err := NewRequest("POST", url, body) req, err := NewRequest("POST", url, body)
if err != nil { if err != nil {
......
...@@ -15,6 +15,7 @@ import ( ...@@ -15,6 +15,7 @@ import (
"io" "io"
"io/ioutil" "io/ioutil"
"net" "net"
"net/http"
. "net/http" . "net/http"
"net/http/httptest" "net/http/httptest"
"net/url" "net/url"
...@@ -1610,6 +1611,42 @@ func TestIdleConnChannelLeak(t *testing.T) { ...@@ -1610,6 +1611,42 @@ func TestIdleConnChannelLeak(t *testing.T) {
} }
} }
// Verify the status quo: that the Client.Post function coerces its
// body into a ReadCloser if it's a Closer, and that the Transport
// then closes it.
func TestTransportClosesRequestBody(t *testing.T) {
defer afterTest(t)
ts := httptest.NewServer(http.HandlerFunc(func(w ResponseWriter, r *Request) {
io.Copy(ioutil.Discard, r.Body)
}))
defer ts.Close()
tr := &Transport{}
defer tr.CloseIdleConnections()
cl := &Client{Transport: tr}
closes := 0
res, err := cl.Post(ts.URL, "text/plain", countCloseReader{&closes, strings.NewReader("hello")})
if err != nil {
t.Fatal(err)
}
res.Body.Close()
if closes != 1 {
t.Errorf("closes = %d; want 1", closes)
}
}
type countCloseReader struct {
n *int
io.Reader
}
func (cr countCloseReader) Close() error {
(*cr.n)++
return nil
}
// rgz is a gzip quine that uncompresses to itself. // rgz is a gzip quine that uncompresses to itself.
var rgz = []byte{ var rgz = []byte{
0x1f, 0x8b, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x8b, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00,
......
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