Merge lp:~jameinel/goose/transfer-content-length-1124561 into lp:goose

Proposed by John A Meinel
Status: Merged
Approved by: John A Meinel
Approved revision: 98
Merged at revision: 97
Proposed branch: lp:~jameinel/goose/transfer-content-length-1124561
Merge into: lp:goose
Diff against target: 120 lines (+52/-7)
2 files modified
http/client.go (+1/-0)
http/client_test.go (+51/-7)
To merge this branch: bzr merge lp:~jameinel/goose/transfer-content-length-1124561
Reviewer Review Type Date Requested Status
Juju Engineering Pending
Review via email: mp+170976@code.launchpad.net

Commit message

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://codereview.appspot.com/10465043/

Description of the change

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://codereview.appspot.com/10465043/

To post a comment you must log in.
Revision history for this message
John A Meinel (jameinel) wrote :
Download full text (5.1 KiB)

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.Statu...

Read more...

Revision history for this message
Dave Cheney (dave-cheney) wrote :

LGTM. I can't believe that bug in nginx took SO LONG to get fixed.

On Sun, Jun 23, 2013 at 7:17 PM, John A Meinel <email address hidden>wrote:

> The proposal to merge lp:~jameinel/goose/transfer-content-length-1124561
> into lp:goose has been updated.
>
> Description changed to:
>
> 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://codereview.appspot.com/10465043/
>
>
> For more details, see:
>
> https://code.launchpad.net/~jameinel/goose/transfer-content-length-1124561/+merge/170976
> --
>
> https://code.launchpad.net/~jameinel/goose/transfer-content-length-1124561/+merge/170976
> Your team juju hackers is requested to review the proposed merge of
> lp:~jameinel/goose/transfer-content-length-1124561 into lp:goose.
>

Revision history for this message
Martin Packman (gz) wrote :

LGTM, let's land this so it's in the next juju-core release.

https://codereview.appspot.com/10465043/diff/1/http/client_test.go
File http/client_test.go (right):

https://codereview.appspot.com/10465043/diff/1/http/client_test.go#newcode60
http/client_test.go:60: emptyBody := "<no-response-yet>"
Why not just the empty string here?

https://codereview.appspot.com/10465043/

97. By John A Meinel

feedback from dfc.

Revision history for this message
John A Meinel (jameinel) wrote :

Please take a look.

https://codereview.appspot.com/10465043/diff/1/http/client_test.go
File http/client_test.go (right):

https://codereview.appspot.com/10465043/diff/1/http/client_test.go#newcode59
http/client_test.go:59: headers := http.Header{}
On 2013/06/26 23:48:37, dfc wrote:
> var headers http.Header

Care to explain why one would be preferred to the other?

https://codereview.appspot.com/10465043/diff/1/http/client_test.go#newcode60
http/client_test.go:60: emptyBody := "<no-response-yet>"
On 2013/06/26 14:59:43, gz wrote:
> Why not just the empty string here?

I was distinguishing between "the body read from remote was empty" and
"I didn't get to the point of reading the content".

I can probably switch back, though.

https://codereview.appspot.com/10465043/diff/1/http/client_test.go#newcode110
http/client_test.go:110: c.Assert(body, NotNil)
On 2013/06/26 23:48:37, dfc wrote:
> this is weird, i cannot see how body will ever not be nil

body is a pointer to a string, and when we get the response from the
server, we point that to the contents of the request.

Why would it be nil?

https://codereview.appspot.com/10465043/

Revision history for this message
John A Meinel (jameinel) wrote :
98. By John A Meinel

Use a channel, since dfc didn't like the string pointer

Revision history for this message
John A Meinel (jameinel) wrote :
Revision history for this message
Dimiter Naydenov (dimitern) wrote :

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'http/client.go'
--- http/client.go 2013-04-19 09:19:53 +0000
+++ http/client.go 2013-06-27 06:51:25 +0000
@@ -209,6 +209,7 @@
209 req.Header.Add(header, value)209 req.Header.Add(header, value)
210 }210 }
211 }211 }
212 req.ContentLength = int64(len(reqData))
212 resp, err = c.Do(req)213 resp, err = c.Do(req)
213 if err != nil {214 if err != nil {
214 return nil, errors.Newf(err, "failed executing the request %s", URL)215 return nil, errors.Newf(err, "failed executing the request %s", URL)
215216
=== modified file 'http/client_test.go'
--- http/client_test.go 2013-02-22 00:36:43 +0000
+++ http/client_test.go 2013-06-27 06:51:25 +0000
@@ -1,6 +1,9 @@
1package http1package http
22
3import (3import (
4 "bytes"
5 "fmt"
6 "io/ioutil"
4 . "launchpad.net/gocheck"7 . "launchpad.net/gocheck"
5 "launchpad.net/goose/testing/httpsuite"8 "launchpad.net/goose/testing/httpsuite"
6 "net/http"9 "net/http"
@@ -52,21 +55,25 @@
52 http.Header{"Foo": []string{"Bar"}, "Content-Type": contentTypes, "Accept": contentTypes, "User-Agent": []string{gooseAgent()}})55 http.Header{"Foo": []string{"Bar"}, "Content-Type": contentTypes, "Accept": contentTypes, "User-Agent": []string{gooseAgent()}})
53}56}
5457
55func (s *HTTPClientTestSuite) setupLoopbackRequest() (*http.Header, *Client) {58func (s *HTTPClientTestSuite) setupLoopbackRequest() (*http.Header, chan string, *Client) {
56 headers := http.Header{}59 var headers http.Header
60 bodyChan := make(chan string, 1)
57 handler := func(resp http.ResponseWriter, req *http.Request) {61 handler := func(resp http.ResponseWriter, req *http.Request) {
58 headers = req.Header62 headers = req.Header
63 bodyBytes, _ := ioutil.ReadAll(req.Body)
64 req.Body.Close()
65 bodyChan <- string(bodyBytes)
59 resp.Header().Add("Content-Length", "0")66 resp.Header().Add("Content-Length", "0")
60 resp.WriteHeader(http.StatusNoContent)67 resp.WriteHeader(http.StatusNoContent)
61 resp.Write([]byte{})68 resp.Write([]byte{})
62 }69 }
63 s.Mux.HandleFunc("/", handler)70 s.Mux.HandleFunc("/", handler)
64 client := New()71 client := New()
65 return &headers, client72 return &headers, bodyChan, client
66}73}
6774
68func (s *HTTPClientTestSuite) TestBinaryRequestSetsUserAgent(c *C) {75func (s *HTTPClientTestSuite) TestBinaryRequestSetsUserAgent(c *C) {
69 headers, client := s.setupLoopbackRequest()76 headers, _, client := s.setupLoopbackRequest()
70 req := &RequestData{ExpectedStatus: []int{http.StatusNoContent}}77 req := &RequestData{ExpectedStatus: []int{http.StatusNoContent}}
71 err := client.BinaryRequest("POST", s.Server.URL, "", req, nil)78 err := client.BinaryRequest("POST", s.Server.URL, "", req, nil)
72 c.Assert(err, IsNil)79 c.Assert(err, IsNil)
@@ -76,7 +83,7 @@
76}83}
7784
78func (s *HTTPClientTestSuite) TestJSONRequestSetsUserAgent(c *C) {85func (s *HTTPClientTestSuite) TestJSONRequestSetsUserAgent(c *C) {
79 headers, client := s.setupLoopbackRequest()86 headers, _, client := s.setupLoopbackRequest()
80 req := &RequestData{ExpectedStatus: []int{http.StatusNoContent}}87 req := &RequestData{ExpectedStatus: []int{http.StatusNoContent}}
81 err := client.JsonRequest("POST", s.Server.URL, "", req, nil)88 err := client.JsonRequest("POST", s.Server.URL, "", req, nil)
82 c.Assert(err, IsNil)89 c.Assert(err, IsNil)
@@ -85,8 +92,45 @@
85 c.Check(agent, Equals, gooseAgent())92 c.Check(agent, Equals, gooseAgent())
86}93}
8794
95func (s *HTTPClientTestSuite) TestBinaryRequestSetsContentLength(c *C) {
96 headers, bodyChan, client := s.setupLoopbackRequest()
97 content := "binary\ncontent\n"
98 req := &RequestData{
99 ExpectedStatus: []int{http.StatusNoContent},
100 ReqReader: bytes.NewBufferString(content),
101 ReqLength: len(content),
102 }
103 err := client.BinaryRequest("POST", s.Server.URL, "", req, nil)
104 c.Assert(err, IsNil)
105 encoding := headers.Get("Transfer-Encoding")
106 c.Check(encoding, Equals, "")
107 length := headers.Get("Content-Length")
108 c.Check(length, Equals, fmt.Sprintf("%d", len(content)))
109 body, ok := <-bodyChan
110 c.Assert(ok, Equals, true)
111 c.Check(body, Equals, content)
112}
113
114func (s *HTTPClientTestSuite) TestJSONRequestSetsContentLength(c *C) {
115 headers, bodyChan, client := s.setupLoopbackRequest()
116 reqMap := map[string]string{"key": "value"}
117 req := &RequestData{
118 ExpectedStatus: []int{http.StatusNoContent},
119 ReqValue: reqMap,
120 }
121 err := client.JsonRequest("POST", s.Server.URL, "", req, nil)
122 c.Assert(err, IsNil)
123 encoding := headers.Get("Transfer-Encoding")
124 c.Check(encoding, Equals, "")
125 length := headers.Get("Content-Length")
126 body, ok := <-bodyChan
127 c.Assert(ok, Equals, true)
128 c.Check(body, Not(Equals), "")
129 c.Check(length, Equals, fmt.Sprintf("%d", len(body)))
130}
131
88func (s *HTTPClientTestSuite) TestBinaryRequestSetsToken(c *C) {132func (s *HTTPClientTestSuite) TestBinaryRequestSetsToken(c *C) {
89 headers, client := s.setupLoopbackRequest()133 headers, _, client := s.setupLoopbackRequest()
90 req := &RequestData{ExpectedStatus: []int{http.StatusNoContent}}134 req := &RequestData{ExpectedStatus: []int{http.StatusNoContent}}
91 err := client.BinaryRequest("POST", s.Server.URL, "token", req, nil)135 err := client.BinaryRequest("POST", s.Server.URL, "token", req, nil)
92 c.Assert(err, IsNil)136 c.Assert(err, IsNil)
@@ -95,7 +139,7 @@
95}139}
96140
97func (s *HTTPClientTestSuite) TestJSONRequestSetsToken(c *C) {141func (s *HTTPClientTestSuite) TestJSONRequestSetsToken(c *C) {
98 headers, client := s.setupLoopbackRequest()142 headers, _, client := s.setupLoopbackRequest()
99 req := &RequestData{ExpectedStatus: []int{http.StatusNoContent}}143 req := &RequestData{ExpectedStatus: []int{http.StatusNoContent}}
100 err := client.JsonRequest("POST", s.Server.URL, "token", req, nil)144 err := client.JsonRequest("POST", s.Server.URL, "token", req, nil)
101 c.Assert(err, IsNil)145 c.Assert(err, IsNil)

Subscribers

People subscribed via source and target branches