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
1=== modified file 'http/client.go'
2--- http/client.go 2013-04-19 09:19:53 +0000
3+++ http/client.go 2013-06-27 06:51:25 +0000
4@@ -209,6 +209,7 @@
5 req.Header.Add(header, value)
6 }
7 }
8+ req.ContentLength = int64(len(reqData))
9 resp, err = c.Do(req)
10 if err != nil {
11 return nil, errors.Newf(err, "failed executing the request %s", URL)
12
13=== modified file 'http/client_test.go'
14--- http/client_test.go 2013-02-22 00:36:43 +0000
15+++ http/client_test.go 2013-06-27 06:51:25 +0000
16@@ -1,6 +1,9 @@
17 package http
18
19 import (
20+ "bytes"
21+ "fmt"
22+ "io/ioutil"
23 . "launchpad.net/gocheck"
24 "launchpad.net/goose/testing/httpsuite"
25 "net/http"
26@@ -52,21 +55,25 @@
27 http.Header{"Foo": []string{"Bar"}, "Content-Type": contentTypes, "Accept": contentTypes, "User-Agent": []string{gooseAgent()}})
28 }
29
30-func (s *HTTPClientTestSuite) setupLoopbackRequest() (*http.Header, *Client) {
31- headers := http.Header{}
32+func (s *HTTPClientTestSuite) setupLoopbackRequest() (*http.Header, chan string, *Client) {
33+ var headers http.Header
34+ bodyChan := make(chan string, 1)
35 handler := func(resp http.ResponseWriter, req *http.Request) {
36 headers = req.Header
37+ bodyBytes, _ := ioutil.ReadAll(req.Body)
38+ req.Body.Close()
39+ bodyChan <- string(bodyBytes)
40 resp.Header().Add("Content-Length", "0")
41 resp.WriteHeader(http.StatusNoContent)
42 resp.Write([]byte{})
43 }
44 s.Mux.HandleFunc("/", handler)
45 client := New()
46- return &headers, client
47+ return &headers, bodyChan, client
48 }
49
50 func (s *HTTPClientTestSuite) TestBinaryRequestSetsUserAgent(c *C) {
51- headers, client := s.setupLoopbackRequest()
52+ headers, _, client := s.setupLoopbackRequest()
53 req := &RequestData{ExpectedStatus: []int{http.StatusNoContent}}
54 err := client.BinaryRequest("POST", s.Server.URL, "", req, nil)
55 c.Assert(err, IsNil)
56@@ -76,7 +83,7 @@
57 }
58
59 func (s *HTTPClientTestSuite) TestJSONRequestSetsUserAgent(c *C) {
60- headers, client := s.setupLoopbackRequest()
61+ headers, _, client := s.setupLoopbackRequest()
62 req := &RequestData{ExpectedStatus: []int{http.StatusNoContent}}
63 err := client.JsonRequest("POST", s.Server.URL, "", req, nil)
64 c.Assert(err, IsNil)
65@@ -85,8 +92,45 @@
66 c.Check(agent, Equals, gooseAgent())
67 }
68
69+func (s *HTTPClientTestSuite) TestBinaryRequestSetsContentLength(c *C) {
70+ headers, bodyChan, client := s.setupLoopbackRequest()
71+ content := "binary\ncontent\n"
72+ req := &RequestData{
73+ ExpectedStatus: []int{http.StatusNoContent},
74+ ReqReader: bytes.NewBufferString(content),
75+ ReqLength: len(content),
76+ }
77+ err := client.BinaryRequest("POST", s.Server.URL, "", req, nil)
78+ c.Assert(err, IsNil)
79+ encoding := headers.Get("Transfer-Encoding")
80+ c.Check(encoding, Equals, "")
81+ length := headers.Get("Content-Length")
82+ c.Check(length, Equals, fmt.Sprintf("%d", len(content)))
83+ body, ok := <-bodyChan
84+ c.Assert(ok, Equals, true)
85+ c.Check(body, Equals, content)
86+}
87+
88+func (s *HTTPClientTestSuite) TestJSONRequestSetsContentLength(c *C) {
89+ headers, bodyChan, client := s.setupLoopbackRequest()
90+ reqMap := map[string]string{"key": "value"}
91+ req := &RequestData{
92+ ExpectedStatus: []int{http.StatusNoContent},
93+ ReqValue: reqMap,
94+ }
95+ err := client.JsonRequest("POST", s.Server.URL, "", req, nil)
96+ c.Assert(err, IsNil)
97+ encoding := headers.Get("Transfer-Encoding")
98+ c.Check(encoding, Equals, "")
99+ length := headers.Get("Content-Length")
100+ body, ok := <-bodyChan
101+ c.Assert(ok, Equals, true)
102+ c.Check(body, Not(Equals), "")
103+ c.Check(length, Equals, fmt.Sprintf("%d", len(body)))
104+}
105+
106 func (s *HTTPClientTestSuite) TestBinaryRequestSetsToken(c *C) {
107- headers, client := s.setupLoopbackRequest()
108+ headers, _, client := s.setupLoopbackRequest()
109 req := &RequestData{ExpectedStatus: []int{http.StatusNoContent}}
110 err := client.BinaryRequest("POST", s.Server.URL, "token", req, nil)
111 c.Assert(err, IsNil)
112@@ -95,7 +139,7 @@
113 }
114
115 func (s *HTTPClientTestSuite) TestJSONRequestSetsToken(c *C) {
116- headers, client := s.setupLoopbackRequest()
117+ headers, _, client := s.setupLoopbackRequest()
118 req := &RequestData{ExpectedStatus: []int{http.StatusNoContent}}
119 err := client.JsonRequest("POST", s.Server.URL, "token", req, nil)
120 c.Assert(err, IsNil)

Subscribers

People subscribed via source and target branches