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
}