@cryptotaxi247 / kubo / commits / 23d41e082

address comments from CR and fix random failures

License: MIT Signed-off-by: Jeromy <jeromyj@gmail.com>

Jeromy committed Jul 27, 2015 at 09:30 UTC 23d41e082399ec5386f691ce907d38e767f54dff
2 files changed +29 -19
commands/http/client.go
+24 -18
@@ -30,10 +30,18 @@ type Client interface {
30
31 type client struct {
32 serverAddress string
33 + httpClient http.Client
34 }
35
36 func NewClient(address string) Client {
36 - return &client{address}
37 + return &client{
38 + serverAddress: address,
39 + httpClient: http.Client{
40 + Transport: &http.Transport{
41 + DisableKeepAlives: true,
42 + },
43 + },
44 + }
45 }
46
47 func (c *client) Send(req cmds.Request) (cmds.Response, error) {
@@ -85,20 +93,20 @@ func (c *client) Send(req cmds.Request) (cmds.Response, error) {
93
94 // TODO extract string consts?
95 if fileReader != nil {
88 - httpReq.Header.Set("Content-Type", "multipart/form-data; boundary="+fileReader.Boundary())
89 - httpReq.Header.Set("Content-Disposition", "form-data: name=\"files\"")
96 + httpReq.Header.Set(contentTypeHeader, "multipart/form-data; boundary="+fileReader.Boundary())
97 + httpReq.Header.Set(contentDispHeader, "form-data: name=\"files\"")
98 } else {
91 - httpReq.Header.Set("Content-Type", "application/octet-stream")
99 + httpReq.Header.Set(contentTypeHeader, applicationOctetStream)
100 }
101 version := config.CurrentVersionNumber
94 - httpReq.Header.Set("User-Agent", fmt.Sprintf("/go-ipfs/%s/", version))
102 + httpReq.Header.Set(uaHeader, fmt.Sprintf("/go-ipfs/%s/", version))
103
104 ec := make(chan error, 1)
105 rc := make(chan cmds.Response, 1)
106 dc := req.Context().Done()
107
108 go func() {
101 - httpRes, err := http.DefaultClient.Do(httpReq)
109 + httpRes, err := c.httpClient.Do(httpReq)
110 if err != nil {
111 ec <- err
112 return
@@ -182,24 +190,25 @@ func getResponse(httpRes *http.Response, req cmds.Request) (cmds.Response, error
190 res.SetLength(length)
191 }
192
185 - res.SetCloser(httpRes.Body)
193 + rr := &httpResponseReader{httpRes}
194 + res.SetCloser(rr)
195
187 - if contentType != "application/json" {
196 + if contentType != applicationJson {
197 // for all non json output types, just stream back the output
189 - res.SetOutput(&httpResponseReader{httpRes})
198 + res.SetOutput(rr)
199 return res, nil
200
201 } else if len(httpRes.Header.Get(channelHeader)) > 0 {
202 // if output is coming from a channel, decode each chunk
203 outChan := make(chan interface{})
204
196 - go readStreamedJson(req, httpRes, outChan)
205 + go readStreamedJson(req, rr, outChan)
206
207 res.SetOutput((<-chan interface{})(outChan))
208 return res, nil
209 }
210
202 - dec := json.NewDecoder(&httpResponseReader{httpRes})
211 + dec := json.NewDecoder(rr)
212
213 // If we ran into an error
214 if httpRes.StatusCode >= http.StatusBadRequest {
@@ -211,7 +220,7 @@ func getResponse(httpRes *http.Response, req cmds.Request) (cmds.Response, error
220 e.Message = "Command not found."
221 e.Code = cmds.ErrClient
222
214 - case contentType == "text/plain":
223 + case contentType == plainText:
224 // handle non-marshalled errors
225 buf := bytes.NewBuffer(nil)
226 io.Copy(buf, httpRes.Body)
@@ -244,9 +253,9 @@ func getResponse(httpRes *http.Response, req cmds.Request) (cmds.Response, error
253
254 // read json objects off of the given stream, and write the objects out to
255 // the 'out' channel
247 -func readStreamedJson(req cmds.Request, httpRes *http.Response, out chan<- interface{}) {
256 +func readStreamedJson(req cmds.Request, rr io.Reader, out chan<- interface{}) {
257 defer close(out)
249 - dec := json.NewDecoder(&httpResponseReader{httpRes})
258 + dec := json.NewDecoder(rr)
259 outputType := reflect.TypeOf(req.Command().Type)
260
261 ctx := req.Context()
@@ -254,9 +263,7 @@ func readStreamedJson(req cmds.Request, httpRes *http.Response, out chan<- inter
263 for {
264 v, err := decodeTypedVal(outputType, dec)
265 if err != nil {
257 - // since we are just looping reading on the response, the only way to
258 - // know we are 'done' is for the consumer to close the response body.
259 - // doing so doesnt throw an io.EOF, but we want to treat it like one.
266 + // reading on a closed response body is as good as an io.EOF here
267 if !(strings.Contains(err.Error(), "read on closed response body") || err == io.EOF) {
268 log.Error(err)
269 }
@@ -268,7 +275,6 @@ func readStreamedJson(req cmds.Request, httpRes *http.Response, out chan<- inter
275 return
276 case out <- v:
277 }
271 -
278 }
279 }
280
commands/http/handler.go
+5 -1
@@ -36,10 +36,14 @@ const (
36 StreamErrHeader = "X-Stream-Error"
37 streamHeader = "X-Stream-Output"
38 channelHeader = "X-Chunked-Output"
39 + uaHeader = "User-Agent"
40 contentTypeHeader = "Content-Type"
41 contentLengthHeader = "Content-Length"
42 + contentDispHeader = "Content-Disposition"
43 transferEncodingHeader = "Transfer-Encoding"
44 applicationJson = "application/json"
45 + applicationOctetStream = "application/octet-stream"
46 + plainText = "text/plain"
47 )
48
49 var mimeTypes = map[string]string{
@@ -156,7 +160,7 @@ func sendResponse(w http.ResponseWriter, req cmds.Request, res cmds.Response) {
160 return
161 }
162
159 - status := 200
163 + status := http.StatusOK
164 // if response contains an error, write an HTTP error status code
165 if e := res.Error(); e != nil {
166 if e.Code == cmds.ErrClient {