@cryptotaxi247 / kubo / commits / e89f7b8de

use go's built in handling of trailers and dont do custom chunking

License: MIT Signed-off-by: Jeromy <jeromyj@gmail.com> use go1.5 syntax to ensure builds on older versions fail License: MIT Signed-off-by: Jeromy <jeromyj@gmail.com> fix t0230 License: MIT Signed-off-by: Jeromy <jeromyj@gmail.com>

Jeromy committed Aug 28, 2015 at 13:02 UTC e89f7b8ded9b56d14fca5a1dc2906b8ecbe02a8b
4 files changed +21 -79
.travis.yml
+1 -2
@@ -7,8 +7,7 @@ os:
7 language: go
8
9 go:
10 -# - 1.3
11 - - 1.4
10 + - 1.5.1
11
12 env:
13 - TEST_NO_FUSE=1 TEST_VERBOSE=1 TEST_SUITE=test_go_expensive
cmd/ipfs/go_req.go new
+3
@@ -0,0 +1,3 @@
1 +// +build !go1.5
2 +
3 +`IPFS needs to be built with go version 1.5 or greater`
commands/http/handler.go
+8 -75
@@ -1,7 +1,6 @@
1 package http
2
3 import (
4 - "bufio"
4 "errors"
5 "fmt"
6 "io"
@@ -205,6 +204,10 @@ func sendResponse(w http.ResponseWriter, r *http.Request, res cmds.Response, req
204 }
205
206 h := w.Header()
207 +
208 + // Set up our potential trailer
209 + h.Set("Trailer", StreamErrHeader)
210 +
211 if res.Length() > 0 {
212 h.Set(contentLengthHeader, strconv.FormatUint(res.Length(), 10))
213 }
@@ -237,82 +240,12 @@ func sendResponse(w http.ResponseWriter, r *http.Request, res cmds.Response, req
240 return
241 }
242
240 - if err := writeResponse(status, w, out); err != nil {
241 - if strings.Contains(err.Error(), "broken pipe") {
242 - log.Info("client disconnect while writing stream ", err)
243 - return
244 - }
245 -
246 - log.Error("error while writing stream ", err)
247 - }
248 -}
249 -
250 -// Copies from an io.Reader to a http.ResponseWriter.
251 -// Flushes chunks over HTTP stream as they are read (if supported by transport).
252 -func writeResponse(status int, w http.ResponseWriter, out io.Reader) error {
253 - // hijack the connection so we can write our own chunked output and trailers
254 - hijacker, ok := w.(http.Hijacker)
255 - if !ok {
256 - log.Error("Failed to create hijacker! cannot continue!")
257 - return errors.New("Could not create hijacker")
258 - }
259 - conn, writer, err := hijacker.Hijack()
243 + w.WriteHeader(status)
244 + _, err = io.Copy(w, out)
245 if err != nil {
261 - return err
262 - }
263 - defer conn.Close()
264 -
265 - // write status
266 - writer.WriteString(fmt.Sprintf("HTTP/1.1 %d %s\r\n", status, http.StatusText(status)))
267 -
268 - // Write out headers
269 - w.Header().Write(writer)
270 -
271 - // end of headers
272 - writer.WriteString("\r\n")
273 -
274 - // write body
275 - streamErr := writeChunks(out, writer)
276 -
277 - // close body
278 - writer.WriteString("0\r\n")
279 -
280 - // if there was a stream error, write out an error trailer. hopefully
281 - // the client will pick it up!
282 - if streamErr != nil {
283 - writer.WriteString(StreamErrHeader + ": " + sanitizedErrStr(streamErr) + "\r\n")
284 - }
285 - writer.WriteString("\r\n") // close response
286 - writer.Flush()
287 - return streamErr
288 -}
289 -
290 -func writeChunks(r io.Reader, w *bufio.ReadWriter) error {
291 - buf := make([]byte, 32*1024)
292 - for {
293 - n, err := r.Read(buf)
294 -
295 - if n > 0 {
296 - length := fmt.Sprintf("%x\r\n", n)
297 - w.WriteString(length)
298 -
299 - _, err := w.Write(buf[0:n])
300 - if err != nil {
301 - return err
302 - }
303 -
304 - w.WriteString("\r\n")
305 - w.Flush()
306 - }
307 -
308 - if err != nil && err != io.EOF {
309 - return err
310 - }
311 - if err == io.EOF {
312 - break
313 - }
246 + log.Error("err: ", err)
247 + w.Header().Set(StreamErrHeader, sanitizedErrStr(err))
248 }
315 - return nil
249 }
250
251 func sanitizedErrStr(err error) string {
test/sharness/t0230-channel-streaming-http-content-type.sh
+9 -2
@@ -22,11 +22,14 @@ test_ls_cmd() {
22 test_expect_success "Text encoded channel-streaming command output looks good" '
23 printf "HTTP/1.1 200 OK\r\n" >expected_output &&
24 printf "Content-Type: text/plain\r\n" >>expected_output &&
25 + printf "Trailer: X-Stream-Error\r\n" >>expected_output &&
26 printf "Transfer-Encoding: chunked\r\n" >>expected_output &&
27 printf "X-Chunked-Output: 1\r\n" >>expected_output &&
28 + printf "Transfer-Encoding: chunked\r\n" >>expected_output &&
29 printf "\r\n" >>expected_output &&
30 echo QmRmPLc1FsPAn8F8F9DQDEYADNX5ER2sgqiokEvqnYknVW >>expected_output &&
29 - test_cmp expected_output actual_output
31 + cat actual_output | grep -vE Date > cleaned_output &&
32 + test_cmp expected_output cleaned_output
33 '
34
35 test_expect_success "JSON encoded channel-streaming command succeeds" '
@@ -39,8 +42,10 @@ test_ls_cmd() {
42 test_expect_success "JSON encoded channel-streaming command output looks good" '
43 printf "HTTP/1.1 200 OK\r\n" >expected_output &&
44 printf "Content-Type: application/json\r\n" >>expected_output &&
45 + printf "Trailer: X-Stream-Error\r\n" >>expected_output &&
46 printf "Transfer-Encoding: chunked\r\n" >>expected_output &&
47 printf "X-Chunked-Output: 1\r\n" >>expected_output &&
48 + printf "Transfer-Encoding: chunked\r\n" >>expected_output &&
49 printf "\r\n" >>expected_output &&
50 cat <<-\EOF >>expected_output &&
51 {
@@ -48,8 +53,10 @@ test_ls_cmd() {
53 "Err": ""
54 }
55 EOF
56 + printf "\n" >> expected_output &&
57 perl -pi -e '"'"'chomp if eof'"'"' expected_output &&
52 - test_cmp expected_output actual_output
58 + cat actual_output | grep -vE Date > cleaned_output &&
59 + test_cmp expected_output cleaned_output
60 '
61 }
62