Reviewers: mp+170976_code.launchpad.net,
Message: Please take a look.
Description: http/client: Set Content-Length
The net/http.Request object takes a Reader so you have to set ContentLength as an attribute or it will not set in in the POST request.
Fixes bug #1124561.
Oddly enough, we always buffer everything anyway, (probably to handle retries?). I would have thought for at least BinaryRequest we would have not touched the io.Reader that we got.
https://code.launchpad.net/~jameinel/goose/transfer-content-length-1124561/+merge/170976
(do not edit description out of merge proposal)
Please review this at https://codereview.appspot.com/10465043/
Affected files: A [revision details] M http/client.go M http/client_test.go
Index: [revision details] === added file '[revision details]' --- [revision details] 2012-01-01 00:00:00 +0000 +++ [revision details] 2012-01-01 00:00:00 +0000 @@ -0,0 +1,2 @@ +Old revision: <email address hidden> +New revision: <email address hidden>
Index: http/client.go === modified file 'http/client.go' --- http/client.go 2013-04-19 09:19:53 +0000 +++ http/client.go 2013-06-23 07:53:30 +0000 @@ -209,6 +209,7 @@ req.Header.Add(header, value) } } + req.ContentLength = int64(len(reqData)) resp, err = c.Do(req) if err != nil { return nil, errors.Newf(err, "failed executing the request %s", URL)
Index: http/client_test.go === modified file 'http/client_test.go' --- http/client_test.go 2013-02-22 00:36:43 +0000 +++ http/client_test.go 2013-06-23 07:53:30 +0000 @@ -1,6 +1,9 @@ package http
import ( + "bytes" + "fmt" + "io/ioutil" . "launchpad.net/gocheck" "launchpad.net/goose/testing/httpsuite" "net/http" @@ -52,21 +55,27 @@ http.Header{"Foo": []string{"Bar"}, "Content-Type": contentTypes, "Accept": contentTypes, "User-Agent": []string{gooseAgent()}}) }
-func (s *HTTPClientTestSuite) setupLoopbackRequest() (*http.Header, *Client) { +func (s *HTTPClientTestSuite) setupLoopbackRequest() (*http.Header, *string, *Client) { headers := http.Header{} + emptyBody := "<no-response-yet>" + body := &emptyBody handler := func(resp http.ResponseWriter, req *http.Request) { headers = req.Header + bodyBytes, _ := ioutil.ReadAll(req.Body) + content := string(bodyBytes) + *body = content + req.Body.Close() resp.Header().Add("Content-Length", "0") resp.WriteHeader(http.StatusNoContent) resp.Write([]byte{}) } s.Mux.HandleFunc("/", handler) client := New() - return &headers, client + return &headers, body, client }
func (s *HTTPClientTestSuite) TestBinaryRequestSetsUserAgent(c *C) { - headers, client := s.setupLoopbackRequest() + headers, _, client := s.setupLoopbackRequest() req := &RequestData{ExpectedStatus: []int{http.StatusNoContent}} err := client.BinaryRequest("POST", s.Server.URL, "", req, nil) c.Assert(err, IsNil) @@ -76,7 +85,7 @@ }
func (s *HTTPClientTestSuite) TestJSONRequestSetsUserAgent(c *C) { - headers, client := s.setupLoopbackRequest() + headers, _, client := s.setupLoopbackRequest() req := &RequestData{ExpectedStatus: []int{http.StatusNoContent}} err := client.JsonRequest("POST", s.Server.URL, "", req, nil) c.Assert(err, IsNil) @@ -85,8 +94,42 @@ c.Check(agent, Equals, gooseAgent()) }
+func (s *HTTPClientTestSuite) TestBinaryRequestSetsContentLength(c *C) { + headers, body, client := s.setupLoopbackRequest() + content := "binary\ncontent\n" + req := &RequestData{ + ExpectedStatus: []int{http.StatusNoContent}, + ReqReader: bytes.NewBufferString(content), + ReqLength: len(content), + } + err := client.BinaryRequest("POST", s.Server.URL, "", req, nil) + c.Assert(err, IsNil) + encoding := headers.Get("Transfer-Encoding") + c.Check(encoding, Equals, "") + length := headers.Get("Content-Length") + c.Assert(body, NotNil) + c.Check(length, Equals, fmt.Sprintf("%d", len(content))) + c.Check(*body, Equals, content) +} + +func (s *HTTPClientTestSuite) TestJSONRequestSetsContentLength(c *C) { + headers, body, client := s.setupLoopbackRequest() + reqMap := map[string]string{"key": "value"} + req := &RequestData{ + ExpectedStatus: []int{http.StatusNoContent}, + ReqValue: reqMap, + } + err := client.JsonRequest("POST", s.Server.URL, "", req, nil) + c.Assert(err, IsNil) + encoding := headers.Get("Transfer-Encoding") + c.Check(encoding, Equals, "") + length := headers.Get("Content-Length") + c.Assert(body, NotNil) + c.Check(length, Equals, fmt.Sprintf("%d", len(*body))) +} + func (s *HTTPClientTestSuite) TestBinaryRequestSetsToken(c *C) { - headers, client := s.setupLoopbackRequest() + headers, _, client := s.setupLoopbackRequest() req := &RequestData{ExpectedStatus: []int{http.StatusNoContent}} err := client.BinaryRequest("POST", s.Server.URL, "token", req, nil) c.Assert(err, IsNil) @@ -95,7 +138,7 @@ }
func (s *HTTPClientTestSuite) TestJSONRequestSetsToken(c *C) { - headers, client := s.setupLoopbackRequest() + headers, _, client := s.setupLoopbackRequest() req := &RequestData{ExpectedStatus: []int{http.StatusNoContent}} err := client.JsonRequest("POST", s.Server.URL, "token", req, nil) c.Assert(err, IsNil)
« Back to merge proposal
Reviewers: mp+170976_ code.launchpad. net,
Message:
Please take a look.
Description:
http/client: Set Content-Length
The net/http.Request object takes a Reader
so you have to set ContentLength as an attribute
or it will not set in in the POST request.
Fixes bug #1124561.
Oddly enough, we always buffer everything anyway,
(probably to handle retries?). I would have thought
for at least BinaryRequest we would have not
touched the io.Reader that we got.
https:/ /code.launchpad .net/~jameinel/ goose/transfer- content- length- 1124561/ +merge/ 170976
(do not edit description out of merge proposal)
Please review this at https:/ /codereview. appspot. com/10465043/
Affected files:
A [revision details]
M http/client.go
M http/client_test.go
Index: [revision details]
=== added file '[revision details]'
--- [revision details] 2012-01-01 00:00:00 +0000
+++ [revision details] 2012-01-01 00:00:00 +0000
@@ -0,0 +1,2 @@
+Old revision: <email address hidden>
+New revision: <email address hidden>
Index: http/client.go Header. Add(header, value)
=== modified file 'http/client.go'
--- http/client.go 2013-04-19 09:19:53 +0000
+++ http/client.go 2013-06-23 07:53:30 +0000
@@ -209,6 +209,7 @@
req.
}
}
+ req.ContentLength = int64(len(reqData))
resp, err = c.Do(req)
if err != nil {
return nil, errors.Newf(err, "failed executing the request %s", URL)
Index: http/client_test.go test.go'
=== modified file 'http/client_
--- http/client_test.go 2013-02-22 00:36:43 +0000
+++ http/client_test.go 2013-06-23 07:53:30 +0000
@@ -1,6 +1,9 @@
package http
import ( net/gocheck" net/goose/ testing/ httpsuite" Header{ "Foo": []string{"Bar"}, "Content-Type": gooseAgent( )}})
+ "bytes"
+ "fmt"
+ "io/ioutil"
. "launchpad.
"launchpad.
"net/http"
@@ -52,21 +55,27 @@
http.
contentTypes, "Accept": contentTypes, "User-Agent": []string{
}
-func (s *HTTPClientTest Suite) setupLoopbackRe quest() (*http.Header, Suite) setupLoopbackRe quest() (*http.Header, iter, req *http.Request) { ReadAll( req.Body) Header( ).Add(" Content- Length" , "0") WriteHeader( http.StatusNoCo ntent) Write([ ]byte{} ) HandleFunc( "/", handler)
*Client) {
+func (s *HTTPClientTest
*string, *Client) {
headers := http.Header{}
+ emptyBody := "<no-response-yet>"
+ body := &emptyBody
handler := func(resp http.ResponseWr
headers = req.Header
+ bodyBytes, _ := ioutil.
+ content := string(bodyBytes)
+ *body = content
+ req.Body.Close()
resp.
resp.
resp.
}
s.Mux.
client := New()
- return &headers, client
+ return &headers, body, client
}
func (s *HTTPClientTest Suite) TestBinaryReque stSetsUserAgent (c *C) { Request( ) Request( ) ExpectedStatus: []int{http. StatusNoContent }} BinaryRequest( "POST", s.Server.URL, "", req, nil)
- headers, client := s.setupLoopback
+ headers, _, client := s.setupLoopback
req := &RequestData{
err := client.
c.Assert(err, IsNil)
@@ -76,7 +85,7 @@
}
func (s *HTTPClientTest Suite) TestJSONRequest SetsUserAgent( c *C) { Request( ) Request( ) ExpectedStatus: []int{http. StatusNoContent }} JsonRequest( "POST", s.Server.URL, "", req, nil)
- headers, client := s.setupLoopback
+ headers, _, client := s.setupLoopback
req := &RequestData{
err := client.
c.Assert(err, IsNil)
@@ -85,8 +94,42 @@
c.Check(agent, Equals, gooseAgent())
}
+func (s *HTTPClientTest Suite) TestBinaryReque stSetsContentLe ngth(c *C) { Request( ) StatusNoContent }, String( content) , BinaryRequest( "POST", s.Server.URL, "", req, nil) Get("Transfer- Encoding" ) Get("Content- Length" ) Suite) TestJSONRequest SetsContentLeng th(c *C) { Request( ) string{ "key": "value"} StatusNoContent }, JsonRequest( "POST", s.Server.URL, "", req, nil) Get("Transfer- Encoding" ) Get("Content- Length" ) Suite) TestBinaryReque stSetsToken( c *C) { Request( ) Request( ) ExpectedStatus: []int{http. StatusNoContent }} BinaryRequest( "POST", s.Server.URL, "token", req, nil)
+ headers, body, client := s.setupLoopback
+ content := "binary\ncontent\n"
+ req := &RequestData{
+ ExpectedStatus: []int{http.
+ ReqReader: bytes.NewBuffer
+ ReqLength: len(content),
+ }
+ err := client.
+ c.Assert(err, IsNil)
+ encoding := headers.
+ c.Check(encoding, Equals, "")
+ length := headers.
+ c.Assert(body, NotNil)
+ c.Check(length, Equals, fmt.Sprintf("%d", len(content)))
+ c.Check(*body, Equals, content)
+}
+
+func (s *HTTPClientTest
+ headers, body, client := s.setupLoopback
+ reqMap := map[string]
+ req := &RequestData{
+ ExpectedStatus: []int{http.
+ ReqValue: reqMap,
+ }
+ err := client.
+ c.Assert(err, IsNil)
+ encoding := headers.
+ c.Check(encoding, Equals, "")
+ length := headers.
+ c.Assert(body, NotNil)
+ c.Check(length, Equals, fmt.Sprintf("%d", len(*body)))
+}
+
func (s *HTTPClientTest
- headers, client := s.setupLoopback
+ headers, _, client := s.setupLoopback
req := &RequestData{
err := client.
c.Assert(err, IsNil)
@@ -95,7 +138,7 @@
}
func (s *HTTPClientTest Suite) TestJSONRequest SetsToken( c *C) { Request( ) Request( ) ExpectedStatus: []int{http. StatusNoContent }} JsonRequest( "POST", s.Server.URL, "token", req, nil)
- headers, client := s.setupLoopback
+ headers, _, client := s.setupLoopback
req := &RequestData{
err := client.
c.Assert(err, IsNil)