@cryptotaxi247 / kubo / commits / 71838adf4

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 }