@cryptotaxi247 / kubo / commits / 8286abaf8

attempt at properly closing http response bodies

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

Jeromy committed Jul 22, 2015 at 10:16 UTC 8286abaf8cf83c63af964fa44e322b43be0b5781
3 files changed +35 -5
commands/http/client.go
+12 -1
@@ -102,12 +102,14 @@ func (c *client) Send(req cmds.Request) (cmds.Response, error) {
102 ec <- err
103 return
104 }
105 +
106 // using the overridden JSON encoding in request
107 res, err := getResponse(httpRes, req)
108 if err != nil {
109 ec <- err
110 return
111 }
112 +
113 rc <- res
114 }()
115
@@ -179,6 +181,8 @@ func getResponse(httpRes *http.Response, req cmds.Request) (cmds.Response, error
181 res.SetLength(length)
182 }
183
184 + res.SetCloser(httpRes.Body)
185 +
186 if len(httpRes.Header.Get(streamHeader)) > 0 {
187 // if output is a stream, we can just use the body reader
188 res.SetOutput(httpRes.Body)
@@ -202,8 +206,15 @@ func getResponse(httpRes *http.Response, req cmds.Request) (cmds.Response, error
206 } else {
207 err = dec.Decode(&v)
208 }
209 +
210 + // since we are just looping reading on the response, the only way to
211 + // know we are 'done' is for the consumer to close the response body.
212 + // doing so doesnt throw an io.EOF, but we want to treat it like one.
213 + if err != nil && strings.Contains(err.Error(), "read on closed response body") {
214 + err = io.EOF
215 + }
216 if err != nil && err != io.EOF {
206 - fmt.Println(err.Error())
217 + log.Error(err)
218 return
219 }
220
commands/http/handler.go
+7 -4
@@ -171,12 +171,15 @@ func (i internalHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
171 // w.WriteHeader(200)
172 err = copyChunks(applicationJson, w, out)
173 if err != nil {
174 - log.Debug(err)
174 + log.Debug("copy chunks error: ", err)
175 }
176 return
177 }
178
179 - flushCopy(w, out)
179 + err = flushCopy(w, out)
180 + if err != nil {
181 + log.Debug("Flush copy returned an error: ", err)
182 + }
183 }
184
185 func (i Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
@@ -191,8 +194,8 @@ func flushCopy(w http.ResponseWriter, out io.Reader) error {
194 return copyChunks("", w, out)
195 }
196
194 - io.Copy(&flushResponse{w}, out)
195 - return nil
197 + _, err := io.Copy(&flushResponse{w}, out)
198 + return err
199 }
200
201 // Copies from an io.Reader to a http.ResponseWriter.
commands/response.go
+16
@@ -101,6 +101,10 @@ type Response interface {
101 SetLength(uint64)
102 Length() uint64
103
104 + // underlying http connections need to be cleaned up, this is for that
105 + Close() error
106 + SetCloser(io.Closer)
107 +
108 // Marshal marshals out the response into a buffer. It uses the EncodingType
109 // on the Request to chose a Marshaler (Codec).
110 Marshal() (io.Reader, error)
@@ -121,6 +125,7 @@ type response struct {
125 length uint64
126 stdout io.Writer
127 stderr io.Writer
128 + closer io.Closer
129 }
130
131 func (r *response) Request() Request {
@@ -214,6 +219,17 @@ func (r *response) Reader() (io.Reader, error) {
219 return r.out, nil
220 }
221
222 +func (r *response) Close() error {
223 + if r.closer != nil {
224 + return r.closer.Close()
225 + }
226 + return nil
227 +}
228 +
229 +func (r *response) SetCloser(c io.Closer) {
230 + r.closer = c
231 +}
232 +
233 func (r *response) Stdout() io.Writer {
234 return r.stdout
235 }