commands/http: handler: Fixed chunk copier to be able to write response before request is done
Matt Bell committed
Dec 17, 2014 at 18:42 UTC
71838adf4983e79c87e186e62d99f0e3044f947e
1 file changed
+41
-8
commands/http/handler.go
+41
-8
@@ -2,6 +2,7 @@ package http
2
3
import (
4
"errors"
5
+ "fmt"
6
"io"
7
"net/http"
8
@@ -84,8 +85,10 @@ func (i Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
85
}
86
87
// if the res output is a channel, set a custom header for it
88
+ isChan := false
89
if _, ok := res.Output().(chan interface{}); ok {
90
w.Header().Set(channelHeader, "1")
91
+ isChan = true
92
}
93
94
// if response contains an error, write an HTTP error status code
@@ -105,34 +108,64 @@ func (i Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
108
return
109
}
110
108
- err = copyChunks(w, out)
109
- if err != nil {
110
- log.Error(err)
111
+ if isChan {
112
+ err = copyChunks(w, out)
113
+ if err != nil {
114
+ log.Error(err)
115
+ fmt.Println(err)
116
+ }
117
+ return
118
}
119
+
120
+ io.Copy(w, out)
121
}
122
123
// Copies from an io.Reader to a http.ResponseWriter.
124
// Flushes chunks over HTTP stream as they are read (if supported by transport).
125
func copyChunks(w http.ResponseWriter, out io.Reader) error {
126
+ hijacker, ok := w.(http.Hijacker)
127
+ if !ok {
128
+ return errors.New("Could not create hijacker")
129
+ }
130
+ conn, writer, err := hijacker.Hijack()
131
+ if err != nil {
132
+ return err
133
+ }
134
+ defer conn.Close()
135
+
136
+ writer.WriteString("HTTP/1.1 200 OK\r\n")
137
+ writer.WriteString(contentTypeHeader + ": application/json\r\n")
138
+ writer.WriteString(transferEncodingHeader + ": chunked\r\n")
139
+ writer.WriteString(channelHeader + ": 1\r\n\r\n")
140
+
141
buf := make([]byte, 32*1024)
142
143
for {
144
n, err := out.Read(buf)
145
146
if n > 0 {
123
- _, err := w.Write(buf[0:n])
147
+ length := fmt.Sprintf("%x\r\n", n)
148
+ writer.WriteString(length)
149
+
150
+ _, err := writer.Write(buf[0:n])
151
if err != nil {
152
return err
153
}
154
128
- if f, ok := w.(http.Flusher); ok {
129
- f.Flush()
130
- }
155
+ writer.WriteString("\r\n")
156
+ writer.Flush()
157
}
158
133
- if err != nil {
159
+ if err != nil && err != io.EOF {
160
return err
161
}
162
+ if err == io.EOF {
163
+ break
164
+ }
165
}
166
+
167
+ writer.WriteString("0\r\n\r\n")
168
+ writer.Flush()
169
+
170
return nil
171
}