diff --git a/commands/http/client.go b/commands/http/client.go index cebdc314b..8dccfcf21 100644 --- a/commands/http/client.go +++ b/commands/http/client.go @@ -102,12 +102,14 @@ func (c *client) Send(req cmds.Request) (cmds.Response, error) { ec <- err return } + // using the overridden JSON encoding in request res, err := getResponse(httpRes, req) if err != nil { ec <- err return } + rc <- res }() @@ -179,6 +181,8 @@ func getResponse(httpRes *http.Response, req cmds.Request) (cmds.Response, error res.SetLength(length) } + res.SetCloser(httpRes.Body) + if len(httpRes.Header.Get(streamHeader)) > 0 { // if output is a stream, we can just use the body reader res.SetOutput(httpRes.Body) @@ -202,8 +206,15 @@ func getResponse(httpRes *http.Response, req cmds.Request) (cmds.Response, error } else { err = dec.Decode(&v) } + + // since we are just looping reading on the response, the only way to + // know we are 'done' is for the consumer to close the response body. + // doing so doesnt throw an io.EOF, but we want to treat it like one. + if err != nil && strings.Contains(err.Error(), "read on closed response body") { + err = io.EOF + } if err != nil && err != io.EOF { - fmt.Println(err.Error()) + log.Error(err) return } diff --git a/commands/http/handler.go b/commands/http/handler.go index 8d44b8601..3e7de8e7a 100644 --- a/commands/http/handler.go +++ b/commands/http/handler.go @@ -171,12 +171,15 @@ func (i internalHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { // w.WriteHeader(200) err = copyChunks(applicationJson, w, out) if err != nil { - log.Debug(err) + log.Debug("copy chunks error: ", err) } return } - flushCopy(w, out) + err = flushCopy(w, out) + if err != nil { + log.Debug("Flush copy returned an error: ", err) + } } func (i Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { @@ -191,8 +194,8 @@ func flushCopy(w http.ResponseWriter, out io.Reader) error { return copyChunks("", w, out) } - io.Copy(&flushResponse{w}, out) - return nil + _, err := io.Copy(&flushResponse{w}, out) + return err } // Copies from an io.Reader to a http.ResponseWriter. diff --git a/commands/response.go b/commands/response.go index 657dd0403..a40c048df 100644 --- a/commands/response.go +++ b/commands/response.go @@ -101,6 +101,10 @@ type Response interface { SetLength(uint64) Length() uint64 + // underlying http connections need to be cleaned up, this is for that + Close() error + SetCloser(io.Closer) + // Marshal marshals out the response into a buffer. It uses the EncodingType // on the Request to chose a Marshaler (Codec). Marshal() (io.Reader, error) @@ -121,6 +125,7 @@ type response struct { length uint64 stdout io.Writer stderr io.Writer + closer io.Closer } func (r *response) Request() Request { @@ -214,6 +219,17 @@ func (r *response) Reader() (io.Reader, error) { return r.out, nil } +func (r *response) Close() error { + if r.closer != nil { + return r.closer.Close() + } + return nil +} + +func (r *response) SetCloser(c io.Closer) { + r.closer = c +} + func (r *response) Stdout() io.Writer { return r.stdout }